最近在看《深入linux 内核架构》 内存管理的部分,写一下博客,做写总结,记录
3.1和3.2节的主要内容
1.UMA和NUMA 类型的计算机对内存的管理方式的影响
UMA,uniform memory access 一致性内存访问,在smp系统中,每个处理器访问各个内存区的速度是一样的
NUMA,non-uniform memory access 非一致性内存访问,每个cpu都有本地的内存,可以支持特别快速的访问,各个处理器之间用总线连起来,以支持对其他cpu的本地内存的访问,当然访问速度要比本地内存慢,下图可以很好的反映UMA 和NUMA 结构的区别:
内核对于UMA 和NUMA 类型的计算机都是以结点的方式来管理,对于UMA的计算机,其实就相当于只有一个NUMA节点的伪NUMA系统
2.linux 内核中表示内存三个数据结构,以及其关系
struct pglist_data:表示结点,每个结点关联到一个处理器,每个结点都会有三种类型的内存域,DMA,NORMAL,HIGHMEM,只有
NORMAL的内存域会保证在每一个结点都有,其他两种类型的内存域有可能有,也有可能没有,pglist_data 数据结构是通过单链表来组织的
struct zone:表示内存域,就是一种类型的内存的集合,内存域会用一个数组来组织属于本域的页帧,page 表示的实例
struct page:页帧,内存管理的最小单元,在IA-32系统中标准页长度是4KiB,通过PAGE_SIZE 指定。PAGE_SIZE 宏定义如下:
#define PAGE_SHIFT 12
#define PAGE_SIZE (1 << PAGE_SHIFT)
三者的关系如下图所示:
3.三个数据结构的成员
-
typedef struct pglist_data {
-
struct zone node_zones[MAX_NR_ZONES]; /*本结点中各种内存域的数组,保存的都是真实的zone ,而不是zone的指针,不存在的域填0*/
-
struct zonelist node_zonelists[MAX_ZONELISTS];/*备用结点,如果当前结点没有可用空间的时候,可以使用备用结点的空间*/
-
int nr_zones; /*结点不同内存域的数目,具体怎么记录的不清楚,到后面看到使用的是来补充*/
-
struct page *node_mem_map; /*指向page 实例的指针,包括结点所有内存域的页帧,就是pglist_data 中也有page*/
-
struct bootmem_data *bdata;/*指向自举内存分配器数据结构实例,在内存管理子系统初始化之前需要的内存,就通过自举内存分配器提供*/
-
-
unsigned long node_start_pfn;/*NUMA结点的第一个页帧的逻辑编号,所以结点的页帧是依次编号的,每个页帧的编号都是全局唯一的,不止是结点内唯一,在UMA 系统中,这个值总是0,因为只有一个结点,而且是从0开始编号的*/
-
unsigned long node_present_pages; /*结点中页帧数目,包括所有内存域的 */
-
unsigned long node_spanned_pages; /* total size of physical page range, including holes */
-
-
int node_id; /*NUMA 结点编号*/
-
stuct pglist_data *pgdat_next; /*指向下一个内存结点的指针*/
-
-
/*以下的三个成员都是与交换相关的,到时候看到在回来补充*/
-
wait_queue_head_t kswapd_wait;
-
struct task_struct *kswapd; /* Protected by lock_memory_hotplug() */
-
int kswapd_max_order;
-
-
} pg_data_t;
-
struct zone {
-
/*通常由页分配器访问的字段*/
-
unsigned long pages_min,pages_low,pages_high;/*是页换出时候的几个阈值*/
-
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];/*伙伴系统使用的,每个元素表示某种固定长度的连续内存区域,这只是一个起点*/
-
ZONE_PADDING(_pad1_)
-
-
/*通常由页面回收扫描程序访问的字段*/
-
spinlock_t lru_lock;
-
struct list_head active_list; /*活动页的集合,访问频繁称为活动,反之称为不活动*/
-
struct list_head inactive_list;
-
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];/*内存域的统计信息*/
-
int prev_priority;
-
-
ZONE_PADDING(_pad2_)
-
-
/*很少使用或者大多数情况下只读的字段*/
-
wait_queue_head_t *wait_table;
-
unsigned long wait_table_hash_nr_entries;
-
unsigned long wait_table_bits;
-
-
/*支持不连续内存模型的字段*/
-
struct pglist_data *zone_pgdat;
-
unsigned long zone_start_pfn; /*内存域的第一个页帧的索引,结点也有第一个页帧的索引*/
-
unsigned long spanned_pages;
-
unsigned long present_pages;
-
-
char *name;
-
} ____cacheline_maxaligned_in_smp;
-
-
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; /*指向slab指针*/
-
struct page *first_page;/*内核可以把多个毗连的也合并为较大的复合页,在这个复合页中,第一个页成为head page,其余的都成为tail page ,所有的tail page 中都会通过成员first_page记录自己所在的复合页的head page ,*/
-
};
-
-
union {
-
pgoff_t index;
-
void *freelist ;
-
};
-
struct list_head lru; /*链表头,用于把page 放到各种链表中的*/
-
#if defined (WANT_PAGE_VIRTUAL)
-
void *virtual; /*用于高端内存的区域的页*/
-
#endif
-
}
目前只是对这些数据结构成员有个大概的了解,通过后面的学习,才能深入了解各个成员的作用。
阅读(1769) | 评论(0) | 转发(0) |