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

UMA(一致内存访问,uniformmemory access): 计算将内存以连续的方式组织起来。SMP中每个cpu访问各内存区具有一样的速度

NUMA(非一致内存访问,non-uniformmemory access):SMP中的各个cpu都有本地的内存,可支持快速访问。各个cpu之间通过总线连接,对其它cpu的内存的访问将会慢于对自己内存的访问。结构如下图:

(N)UMA 模型中的内存组织------《深入Linux内核架构》笔记_第1张图片

在内核中内存划分为节点,每个节点关联到一个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成员是没有的。  

(N)UMA 模型中的内存组织------《深入Linux内核架构》笔记_第2张图片

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


//节点(简化版)
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 */



你可能感兴趣的:(struct,list,活动,table,Access,linux内核)