您的位置:首页 > 运维架构 > 网站架构

N)UMA 模型中的内存组织------《深入Linux内核架构》笔记

2012-12-13 23:12 204 查看
http://blog.csdn.net/daniel_ice/article/details/6833835

UMA(一致内存访问,uniformmemory access): 计算将内存以连续的方式组织起来。SMP中每个cpu访问各内存区具有一样的速度
NUMA(非一致内存访问,non-uniformmemory access):SMP中的各个cpu都有本地的内存,可支持快速访问。各个cpu之间通过总线连接,对其它cpu的内存的访问将会慢于对自己内存的访问。结构如下图:



在内核中内存划分为节点,每个节点关联到一个cpu,在内核中用pg_data_t表示。

各个节点进一步划分为域,在内核中用structzone来表示。对于x86来说,总共有ZONE_DMA,ZONE_NORMAL,ZONE_HIGMENT三个域实例。ZONE_DMA负责对负责分配用于DMA操作的内存,ZONE_NORMAL负责分配可以直接映射到内核段的内存,ZONE_HIGMENT负责分配超出内核段的物理内存(应该是指另外的3GB内存)。
注意:内存域这个概念是对于物理内存而言的,而不是虚拟内存

每个域中会包含一个structfree_area成员,该成员用于实现伙伴系统,管理该区域中的空闲内存页。

页在内核中对应的结构体为structpage,该结构体采用union语法来减少结构体的大小。Page中的mapping指定了页帧所在的地址空间,virtual用于存储该页的虚拟地址,在x86体系中virtual成员是没有的。




上图展示了节点,域,页之间的关系。这里再对每个概念所涉及功能进一步阐述(这里只是简单介绍部分功能,详细信息请参考《深入linux内核架构》3.2节):

[cpp]
view plaincopy

//节点(简化版)
typedef struct pglist_data {
struct zone node_zones[MAX_NR_ZONES];//指明该节点下包含有多少个域
//指向page实例数组的指针,用于描述节点的所有物理内存页,它包含了节点中所有内存域的页
struct page *node_mem_map;
//备用节点的内存域的链表,用于在NUMA中,该节点无法提供内存,需要到其它的节点分配
struct zonelist node_zonelists[MAX_ZONELISTS];
struct bootmem_data *bdata;//用于为分配在系统初始化之前所需要的内存?
}pg_data_t;


//域(简化版,并没有考虑NUMA)
struct zone {
unsigned long watermark[NR_WMARK];//系统在分配页之后,需要保证剩余下了的页的数量大于水印
//当空闲页数低于该值时,读取空闲页将会导致附加的操作被执行,而这一附加的操作是为了躲避能让水印被违反的per-cpucounter drift。
unsigned long percpu_drift_mark;
//分别为各个内存域指定若干的保留页,用于系统的紧急内存分配
unsigned long lowmem_reserve[MAX_NR_ZONES];
struct per_cpu_pageset pageset[NR_CPUS];//用于存放冷热页,在高速缓存中的页称为热页。
struct free_area free_area[MAX_ORDER];//用于实现伙伴系统
spinlock_t lock;//自旋锁
ZONE_PADDING(_pad1_)//用于实现将每个自旋锁放置于不同的缓存行,x86中每个缓存行为32Bytes
//以下两个成员用于页面回收程序使用
spinlock_t lru_lock;
struct zone_lru {
struct list_head list;
}lru[NR_LRU_LISTS];//分别保存活动页和非活动页。页访问频繁及认为为活动页
struct zone_reclaim_stat reclaim_stat;
unsigned long pages_scanned; /* since last reclaim */
unsigned long flags;// 用于描述内存域所处的状态,比如被LOCKED,所有的不能回收
atomic_long_t vm_stat[NR_VM_ZONE_STAT_ITEMS];//用于保存对该域的统计数据,如活动页的数目
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; //内存数量(不包含空洞)
const char *name;//域的名字,内核将很少使用的字段放到结构体的末尾
}____cacheline_internodealigned_in_smp;


//页(简化版),slab,freelist,inuse用于实现slub
struct page {
unsigned long flags ;//记录该页的状态信息,如该页是否被LOCKED,是否脏等等
atomic_t_count;//使用计数,表示内核中引用该页的次数
union {
atomic_t_mapcount;// _mapcount为32位,表示在页表中多少项指向该页
struct {
u16inuse;//用于slub分配器,对象的数目,该成员不需要原子特性
u16objects;
};
};
union {
struct {
//一个指向私有数据的指针,根据页的用途,可以用不同的方式使用该指针
unsigned longprivate;
//指定页帧所在的地址空间,index是页帧在内部的偏移量。当mapping最低位置1时该指针并不指向address_space实例,而是指向anon_vma
struct address_space *mapping;
};
struct kmem_cache *slab;//用于SLUB分配器,指向slab的指针
struct page *first_page;//指向compoundpage中的首页
};
union {
pgoff_tindex;/* Our offset within mapping. */
void *freelist;/* SLUB: freelist req. slablock */
};
struct list_head lru;//用于将页按不同的类别分组,如活动和不活动
#ifdefined(WANT_PAGE_VIRTUAL)
void*virtual;
//在x86体系中,没有该成员
#endif/*WANT_PAGE_VIRTUAL */
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: