#define ALLOC_NO_WATERMARKS 0x01 /* don't check watermarks at all */
#define ALLOC_WMARK_MIN 0x02 /* use pages_min watermark */
#define ALLOC_WMARK_LOW 0x04 /* use pages_low watermark */
#define ALLOC_WMARK_HIGH 0x08 /* use pages_high watermark */
#define ALLOC_HARDER 0x10 /* try to alloc harder */
#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */
#define ALLOC_CPUSET 0x40 /* check for correct cpuset */
-------------------------------------------------------------------------
上述是一些标志位。用来控制内存的分配行为。
1)
#define ALLOC_WMARK_HIGH 0x08 /* use pages_high watermark */
只有内存域的页面数至少为zone->pages_high 才分配页面
2)
#define ALLOC_WMARK_LOW 0x04 /* use pages_low watermark */
只有内存域的页面数至少为zone->pages_low 才分配页面
3)
#define ALLOC_WMARK_MIN 0x02 /* use pages_min watermark */
只有内存域的页面数至少为zone->pages_min 才分配页面
4)
#define ALLOC_NO_WATERMARKS 0x01 /* don't check watermarks at all */
顾名思义,不需要考虑内存域的水位情况。
5)
#define ALLOC_HARDER 0x10 /* try to alloc harder */
这个标志位的含义是通知伙伴系统放宽限制。
代码中有如下
long min = mark;
if (alloc_flags & ALLOC_HARDER)
min -= min / 4;
6)
#define ALLOC_HIGH 0x20 /* __GFP_HIGH set */
在分配高端内存域时,进一步放宽限制
代码中有如下:
if (alloc_flags & ALLOC_HIGH)
min -= min / 2;
----------------------------------------------------------------------------
继续关注 zone_water_mark_ok 这个函数之前,我们需要讲述清楚
1 zone->pages_min
2 zone->pages_low
3 zone->pages_high
page_min page_low page_high是内存域 zone这个结构体的成员变量,是页换出时使用的
水印。如果内存不足,内核将页换出,写入到硬盘上。这三个变量的值指导着交换守护进程
的行为:
1 如果内存域的空闲页面大于 pages_high,表示内存域的状态很好
2 如果内存域的空闲页面低于 pages_low,则内核需要将页换出到硬盘
3 如果内存域的空闲页面低于pages_min,则内存域中空闲页面太少,继续空闲页,页回收工作压力大。
接下来的问题是,如何计算内存域 水印的大小
计算水印之前,首先介绍全局变量 min_free_kbytes 这个值是需要为关键性分配保留的内存空间的最小值,
不能低于128K,不能高于64M,在函数init_per_zone_pages_min 中计算
代码如下
lowmem_kbytes = nr_free_buffer_pages() * (PAGE_SIZE >> 10);
min_free_kbytes = int_sqrt(lowmem_kbytes * 16);
if (min_free_kbytes < 128)
min_free_kbytes = 128;
if (min_free_kbytes > 65536)
min_free_kbytes = 65536;
用户可以通过文件/proc/sys/vm/min_free_kbytes来读取当前的值
好假设我们已经确定了全局变量 min_free_kbytpes的值,接下来我们计算三个水印。
低端内存域和高端内存域是分开计算的,从下面的步骤中可以体会
A 将min_free_kbytes 折合成页面数 pages_min。
B 计算所有低端内存域的内存页总数,保存在lowmem_pages
for_each_zone(zone) {
if (!is_highmem(zone))
lowmem_pages += zone->present_pages;
}
C 对于每个低端内存域,根据每个内存域的页面多少,按照比例,共留出 pages_min个页面
即
tmp = (zone->present_pages /lowmem_pages) *pgaes_min;
pages_min = tmp;
pages_low = tmp + tmp/4;
page_high = tmp + tmp/2;
D 对于高端内存域 首先也是计算tmp
tmp = (zone->zone->present_pages /lowmem_pages) *pgaes_min;
pages_min = zone->present_pages / 1024;
将pages_min调整到 [SWAP_CLUSTER_MAX ,128]之内。
pages_low = pgaes_min + tmp/4;
pages_high = pages_min + tmp/2;
------------------------------------------------------------------------------------------
解决完水印的计算问题,到了 zone_water_mark_ok
free_pages = 内存域分配完 阶为order的页面数后剩余的页面
如果 free_pages <= min +zpme->lowreserve[classzone_idx] //此处我存在疑惑
则表示不能满足水印条件,不能分配
接下来有一部分代码不太容易理解,我把自己的理解讲述一下,当然不一定正确
代码如下:
for (o = 0; o < order; o++) {
/* At the next order, this order's pages become unavailable */
free_pages -= z->free_area[o].nr_free << o;
/* Require fewer higher order pages to be free */
min >>= 1;
if (free_pages <= min)
return 0;
}
本来,分配完后,只要剩余的页数大于水位,就可以安然返回OK,但是伙伴系统不光要考虑剩余页的总数
还要考虑0 ~order 阶 剩余页的情况, 这个循环其实是为了保证位于高阶和低阶的页大体均衡。
尤其是free_pages比较少,正好位于水印附近的时候,要保证高阶页面总数和低阶的大体均衡。
--------------------------------------------------------------------------------------
遗留的问题:
free_pages <= min + zone->lowreserve[classzone_idx]
这个判断条件中的后半部zone->lowreserve[classzone_idx] 不太明白是什么用处。
阅读(4166) | 评论(2) | 转发(0) |