内存管理是内核最复杂同时也是最重要的一部。其特点在于非常需要处理器和内核之间的协作。
首先内存划分为结点,在内核中表示为pg_data_t,每个结点划分为内存域。
以下的所有数据结构或代码都做了不同程度的精减,一方面是为了保留相关代码,除去细枝末叶,另一方面是为了美观。
结点的数据结构为
<mmzone.h>
typedef struct pglist_data {
struct zone node_zones[MAX_NR_ZONES]; /*内存结点所包含的内存域数组*/
struct zonelist node_zonelists[MAX_ZONELISTS]; /*指定了备用结点及其内存域列表*/
int nr_zones; /*内存域的数目*/
#ifdef CONFIG_FLAT_NODE_MEM_MAP
struct page *node_mem_map; /*node_mem_map是指向page实例数组的指针,它包含了结点中所有内存域的页*/
#endif
struct bootmem_data *bdata; /*bdata指定了用于自举分配器数据结构的实例*/
#ifdef CONFIG_MEMORY_HOTPLUG
#endif
unsigned long node_start_pfn; /*结点内第一个页帧的逻辑编号*/
unsigned long node_present_pages; /* 物理内存页的总数,不包括内存洞 */
unsigned long node_spanned_pages; /* 物理内存页的总长度,包括洞在内 */
int node_id; /*结点id*/
struct pglist_data *pgdata_next; /*下一个内存结点的指针*/
} pg_data_t;
内存域是由枚举来表示的,如下所示
<mmzone.h>
enum zone_type {
#ifdef CONFIG_ZONE_DMA
ZONE_DMA,/*ZONE_DMA表示DMA区域。在IA-32机器上,一般的限制是0~16M。*/
#endif
ZONE_NORMAL,/*ZONE_NORMAL表示可直接映射到内核段的普通内存域。在x86机器上为16M~896M.*/
#ifdef CONFIG_HIGHMEM
ZONE_HIGHMEM,/* ZONE_HIGHMEM标记了超出内核段的物理内存。如在x86机器上,内存为4G,那么896M~4G就为高端内存。*/
#endif
ZONE_MOVABLE, /* ZONE_MOVABLE表示的内存域属于伪内存域,主要用于防止内存碎片。*/
MAX_NR_ZONES/*MAX_NR_ZONES充当结束标记。用于内存域的迭代。*/
};
内存域的结构描述如下:
<mmzone.h>
struct zone {
/*
*pages_min, pages_low, pages_high是水印,用于面换出时的计算
*pages_high表示如果内存域中的空闲页多于此值,则内存域的状态是理想的
*pages_low表示如果内存域中的空闲页低于此值,则内核开始将页换出到硬盘
*pages_min表示如果内存域中的空闲页低于此值,则表示空闲页极少。此时页回收工作压力很大。
*/
unsigned long pages_min, pages_low, pages_high;
/*
*lowmen_reserve表示为各个内存域预留的页数目,用于不能失败的关键性内存分配
*/
unsigned long lowmem_reserve[MAX_NR_ZONES];struct per_cpu_pageset pageset[NR_CPUS]; /* 每个CPU的冷热帧列表*/
spinlock_t lock; /*自旋锁*/
struct free_area free_area[MAX_ORDER];/*用于伙伴系统的数据结构*/spinlock_t lru_lock; /*自旋锁*/
struct list_head active_list; /*活动页的集合,page实例*/
struct list_head inactive_list; /*不活动页的集合, page实例*/
unsigned long nr_scan_active;/*指定回收内存时需要扫描的活动页的数目*/
unsigned long nr_scan_inactive;/*指定回收内存时需要扫描的不活动页的数目*/
unsigned long pages_scanned; /* 指定了上一欠掏出一页以来,有多少页未能成功扫描*/
unsigned long flags; /* 内存域的当前状态 */atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS]; /*内存的统计信息*/
struct pglist_data *zone_pgdat; /*指定pg_data_t实例*/
/* zone_start_pfn == zone_start_paddr >> PAGE_SHIFT */
unsigned long zone_start_pfn; /*内存域的第一个页帧的索引*/
};
页帧的数据结构:
struct page {
unsigned long flags; /* 页帧的标记*/
atomic_t _count; /* 使用记数 */
union {
atomic_t _mapcount; /*内存管理子系统中映射的页表项计数,用于表示页是否已经映射,还用于限制逆向映射搜索*/
unsigned int inuse; /* 用于SLUB分配器:对象的数目*/
};
union {
struct {
unsigned long private; /* 由映射私有,不透明数据*/
struct address_space *mapping; /*映射所在的地址空间*/
};
struct kmem_cache *slab; /* 指向slub的指针 */
struct page *first_page; /* 用于复合页的尾页,指向首页 */
};
union {
pgoff_t index; /* 在映射内的偏移量 */
void *freelist; /* SLUB: freelist req. slab lock */
};
struct list_head lru; /*用于在各种不同的鍡上维护该页*/
#if defined(WANT_PAGE_VIRTUAL)
void *virtual; /*用于高端内存中的页。存储该页的虚拟地址*/
#endif /* WANT_PAGE_VIRTUAL */
};
Linux内存管理 (一) 内存组织,布布扣,bubuko.com