《Linux内核深度解析》第三章 内存学习笔记2
[复制链接]
Linux内存管理是指操作系统对于计算机系统中的内存资源进行有效利用和管理的过程。它包括了内存分配、内存映射等一些方面
一 引导内存分配器
在内核初始化的过程中需要分配内存,内核提供了临时的引导内存分配器,在页分配器和块分配器初始化完毕后,把空闲的物理页交给页分配器管理,丢弃引导内存分配器
早期使用的引导分配器是bootmem,目前正在使用memblock取代bootmem
查看bootmem_data数据结构
typedef struct bootmem_data {
unsigned long node_min_pfn;
unsigned long node_low_pfn;
void *node_bootmem_map;
unsigned long last_end_off;
unsigned long hint_idx;
struct list_head list;
} bootmem_data_t;
Memblock数据结构
truct memblock_type {
unsigned long cnt; /* number of regions */
unsigned long max; /* size of the allocated array */
phys_addr_t total_size; /* size of all regions */
struct memblock_region *regions;
char *name;
};
二伙伴分配器
内核初始化完毕后,使用页分配器管理物理页,当前使用的页分配器是伙伴分配器,伙伴分配器的特点是算法简单
Memblock(引导内存分配器)完成对应的工作后,将未使用的内存释放至伙伴系统,完成伙伴系统的初始化工作。start_kernel()->mm_init()->mem_init()->memblock_free_all()。
伙伴系统是一个结合了2的方幂个分配器和空闲缓冲区合并计技术的内存分配方案。
typedef struct pglist_data {
//... ...
//存储与当前节点相关的内存区域数组
struct zone node_zones[MAX_NR_ZONES];
//MAX_ZONELISTS个备用区域数组
struct zonelist node_zonelists[MAX_ZONELISTS];
int nr_zones; /* 当前节点中填充的区域数量 */
//... ...
} pg_data_t;
struct zonelist {
struct zoneref _zonerefs[MAX_ZONES_PER_ZONELIST + 1];
};
struct zoneref {
struct zone *zone; /* Pointer to actual zone */
int zone_idx; /* zone_idx(zoneref->zone) */
};
网上大佬的分析:内存被分成含有很多页面的大块, 每一块都是2个页面大小的方幂。如果找不到想要的块, 一个大块会被分成两部分, 这两部分彼此就成为伙伴。其中一半被用来分配, 而另一半则空闲。这些块在以后分配的过程中会继续被二分直至产生一个所需大小的块。当一个块被最终释放时, 其伙伴将被检测出来, 如果伙伴也空闲则合并两者。
三 块分配器
为了解决小块内存的分配问题,LINUX内核提供了块分配器,最早实现的块分配器是SLAB分配器。
因为上一个伙伴分配器,buddy是以页框为分配单元,那对于小于一页的内存需求又该如何处理呢,如果直接分配一页,就浪费了宝贵的内存空间,形成了内碎片。
SLAB分配器的作用不仅仅是分配小块内存,更重要的作用是针对经常分配和释放的对象充当缓存。
通用的内存缓存的编程接口
|