深入理解linux虚拟内存管理--02 描述物理内存

几个概念

非一致内存访问 Non-Uniform Memory Access (NUMA)
一致内存访问(UMA)
参考:
NUMA和UMA

在Linux中,内存的每个bank被认为是一个节点(node),并用struct pg_data_t来表示。
系统中的每个node都被一个pgdat_list链表管理,此链表以NULL结尾。
pg_data_t结构体的node_next字段用于链接到下一个节点。

PC这种UMA结构的机器,只使用一个静态pg_data_t变量:contig_page_data

内存中,每个node被分成很多管理区(zone)
struct zone_struct描述(zone_t
zone的类型有:
ZONE_DMA,一般是低端地址的内存,用于设备驱动使用。(x86机器中,16M)
ZONE_NORMAL,由内核直接映射到线性地址空间。(x86机器中,16M~896M)
ZONE_HIGHMEM,预留空间,内核不会直接映射这一部分。(x86机器中,896M~末尾)

内存被划分为页面(page)进行管理
由结构struct page描述,所有的页面结构都存储在一个全局的mem_map数组中。
这个数组通常存放在ZONE_NORMAL的首部。
node、zone、page

 

节点node

linux/mmzone.h
/*
 * The pg_data_t structure is used in machines with CONFIG_DISCONTIGMEM
 * (mostly NUMA machines?) to denote a higher-level memory zone than the
 * zone_struct denotes. 比zone更高一个维度的结构。
 *
 * On NUMA machines, each NUMA node would have a pg_data_t to describe
 * it's memory layout.
 *
 * XXX: we need to move the global memory statistics (active_list, ...)
 *      into the pg_data_t to properly support NUMA.
 */
typedef struct pglist_data {
	zone_t			node_zones[MAX_NR_ZONES];
	zonelist_t		node_zonelists[GFP_ZONEMASK+1];
	int 			nr_zones;
	struct page		*node_mem_map;
	unsigned long	*valid_addr_bitmap;
	struct bootmem_data *bdata;
	unsigned long	node_start_paddr;
	unsigned long	node_start_mapnr;
	unsigned long	node_size;
	int 			node_id;
	struct pglist_data *node_next;
} pg_data_t;
  1. node_zones:该节点包含的管理区,可能有 ZONE_ HIGHMEM,ZONE_ NORMAL和ZONE_ DMA。
  2. node_zonelists:分配内存时,分别从不同的管理区去尝试。三个zone有一个排列顺序排列。
    在调用free_area_init_core()时,通过mm/page_alloc.c文件中的 build_zonelists()建立顺序。
    分配内存时,如果在ZONE_HIGHMEM中分配失败,就到ZONE_ NORMAL,再到ZONE_ DMA中去分配。
  3. nr_zones:该节点中的管理区数目(1~3)。并不是所有的节点都有3个管理区。
  4. node_mem_map:指struct page数组中的第一个页面,struct page代表该节点中的物理页面。
    它将被放置在全局mem_map数组的某个位置。
  5. valid_addr_bitmap:一张描述内存节点中“空洞”的位图,空洞代表并没有实际的内存空间存在。(x86不含空洞)
  6. bdata:指向内存引导期间分配器程序(boot mem allocator),在第5章中有介绍。
  7. node_start_paddr:节点的起始物理地址。无符号长整型并不是最佳选择,因为它会在ia32上被物理地址拓展(PAE)拆散。PAE在第2.7节有讨论。
    更好的解决方法是用页面帧号(PFN)记录该节点的起始物理地址。一个PFN就是一个物理页面的索引号。物理地址转换成PFN:page_phys_addr>>PAGE_SHIFT(物理地址右移22位,一个页的大小是4K即1<<22)。
  8. node_start_mapnr:它指出该节点在全局mem_map中的页面偏移。
    在free_area_init.core()中,通过计算mem_map与该节点的局部mem_map(称为lmem_map)之间的页面数,从而得到页面偏移。
  9. node_size:这个管理区中的页面总数。
  10. node_id:节点的ID号(NID),从0开始。
  11. node_next:指向下一个节点,所在的链表以NULL结尾。
     

管理区zone

zone用于跟踪页面使用情况统计、空闲区域信息、锁信息等。

/*
 * On machines where it is needed (eg PCs) we divide physical memory
 * into multiple physical zones. On a PC we have 3 zones:
 *
 * ZONE_DMA	  < 16 MB	ISA DMA capable memory
 * ZONE_NORMAL	16-896 MB	direct mapped by the kernel
 * ZONE_HIGHMEM	 > 896 MB	only page cache and user processes
 */
typedef struct zone_struct {
	/*
	 * Commonly accessed fields:
	 */
	spinlock_t			lock;
	unsigned long		free_pages;
	unsigned long		pages_min, pages_low, pages_high;
	int					need_balance;

	/*
	 * free areas of different sizes
	 */
	free_area_t			free_area[MAX_ORDER];

	/*
	 * wait_table		-- the array holding the hash table
	 * wait_table_size	-- the size of the hash table array
	 * wait_table_shift	-- wait_table_size
	 * 				== BITS_PER_LONG (1 << wait_table_bits)
	 *
	 * The purpose of all these is to keep track of the people
	 * waiting for a page to become available and make them
	 * runnable again when possible. The trouble is that this
	 * consumes a lot of space, especially when so few things
	 * wait on pages at a given time. So instead of using
	 * per-page waitqueues, we use a waitqueue hash table.
	 *
	 * The bucket discipline is to sleep on the same queue when
	 * colliding and wake all in that wait queue when removing.
	 * When something wakes, it must check to be sure its page is
	 * truly available, a la thundering herd. The cost of a
	 * collision is great, but given the expected load of the
	 * table, they should be so rare as to be outweighed by the
	 * benefits from the saved space.
	 *
	 * __wait_on_page() and unlock_page() in mm/filemap.c, are the
	 * primary users of these fields, and in mm/page_alloc.c
	 * free_area_init_core() performs the initialization of them.
	 */
	wait_queue_head_t	* wait_table;
	unsigned long		wait_table_size;
	unsigned long		wait_table_shift;

	/*
	 * Discontig memory support fields.
	 */
	struct pglist_data	*zone_pgdat;
	struct page			*zone_mem_map;
	unsigned long		zone_start_paddr;
	unsigned long		zone_start_mapnr;

	/*
	 * rarely used fields:
	 */
	char				*name;
	unsigned long		size;
} zone_t;
  1. lock:并行访问时保护该管理区的自旋锁。
  2. free_pages:该管理区中空闲页面的总数
  3. pages_min,pages_low,pages_high:管理区极值。
  4. need_balance:该标志位通知页面换出进程kswapd平衡该管理区。当可用页面的数量达到管理区极值的某一个值时,就需要平衡该管理区了。
  5. free_area:空闲区域位图,由伙伴分配器使用。
  6. wait_table:等待队列的哈希表,该等待队列由等待页面释放的进程组成。它对wait_on_page()和 unlock_page()非常重要。虽然所有的进程都可以在一个队列中等待,但这可能会导致所有等待进程在被唤醒后,都去竞争依旧被锁的页面。大量的进程像这样去尝试竞争一个共享资源,有时被称为惊群效应thundering herd
  7. wait_table_size:该哈希表的大小(等待队列个数),它是2的幂。
  8. wait_table_shift:定义为一个 long 型所对应的位数减去上述表大小的以2为底的对数。
  9. zone_pgdat:指向父pg_data_t。
  10. zone_mem_map:在全局mem_map中该zone引用的第一个struct page。
  11. zone_start_paddr :同node_start_paddr。
  12. zone_start_mapnr:同node_start_mapnr。(该zone在 struct page* mem_map 中的以页面结构struct page 为大小的偏移数)
  13. name:该管理区的字符串名字,“DMA”,“Normal”或者“HighMem”。
  14. size:该管理区的大小,以页面数计算。

管理区极值watermarks

当系统中的可用内存很少时,页面换入换出守护进程kswapd被唤醒开始释放页面(见第10章)。
如果内存压力很大,伙伴分配器也开始释放内存 ,有时候这种情况被引用为direct-reclaim路径。

每个管理区都有三个极值,分别称为pages_low, pages_min 和 pages_high,这些极值用于跟踪一个管理区承受了多大的压力。

pages_min的页面数量在内存初始化阶段由函数free_area_init_core()计算出来,并且是基于页面的管理区大小的一个比率。计算值初始化为ZoneSizeInPages/128。它所能取的最小值是20页(在x86上是80 KB),最大值是255页(在x86上是1 MB)。
管理区极值
每个极值在表示内存不足时的行为都互不相同。

  1. pages_low:在空闲页面数达到pages_low时,伙伴分配器就会唤醒kswapd并开始释放页面。
    pages_low的默认值是pages_min的两倍。
  2. pages_min:当达到pages_min时,伙伴分配器也开始释放页面 (和kswapd的工作一样),这种情况被引用为direct-reclaim路径。
  3. pages_high:kswpad被唤醒并开始释放页面后,在pages_high个页面被释放以前,是不会认为该管理区已经“平衡”的。当达到这个极值后,已经平衡,kswapd就再次睡眠。
    pages_high的默认值是pages_min的三倍.

计算管理区大小

管理区初始化

初始化mem_map

页面page

页面映射到管理区

高端内存

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
作者: [爱尔兰] 戈尔曼(Gorm 出版社: 北京航空航天大学出版社 原作名: Understanding the Linux Virtual Memory Manager 内容简介 · · · · · · 深入理解Linux虚拟内存管理,ISBN:9787810777308,作者:(爱尔兰)戈尔曼著;白洛等 作者简介 · · · · · · Mel Gorman曾获得爱尔兰利马瑞克大学的计算机学士和硕士学位。他的研究领域广泛:从网页开发到摄影机的实时显示系统。Mel Gorman认为,即使是最难以攻克的项目也并没有想象中那么艰难。他曾经还担任过系统管理员,主要管理Linux, 也涉及到Solaris和Windows。现今Mel Gorman是都柏林IBM公司的Java程序开发员。 Mel Gorman的大部分技能都来自于他自己在利马瑞克大学的生活经历,与大学里计算机社区的广泛接触,以及实地工作经验这三者的完美结合。是计算机社区使他接触到了Linux,并相信Linux用途广泛,而绝不仅仅只是一个便利的邮箱地址。这个社区还使他对开放源码软件产生了兴趣,尤其是在Linux内核方面。他永远感激利马瑞克大学为他提供的这个平台,使他认识了许多有识之士,并有两年时间来研究VM。 闲暇时Mel Gorman喜欢和女友凯伦呆在一起,或者弹弹吉他(尽管并不擅长),读读手边的书籍,与朋友和家人(他们避免谈及有关VM的话题)一同消磨时光。又或是制订一些可能并无价值的计划(有时仅仅在想象中完成它们)。只要安迪说服他乘坐游艇是个不错的娱乐项目,他也会去尝试。Mel Gorman还在犹豫着是继续创作关于Linux的文章,还是向从前一样在Linux环境下编写程序,因为后者才是他最初的意愿。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值