现在的位置: 首页 > 综合 > 正文

__zone_watermark_ok分析

2013年03月19日 ⁄ 综合 ⁄ 共 3066字 ⁄ 字号 评论关闭

__zone_watermark_ok分析

最近在学习linux 内存管理这一块。
看到了函数__zone_watermark_ok。想起来之前也曾经见过该函数,当时是在分析init.rc的内存,最终也看到了这个函数,不过当时对其并不是很理解。
最近又遇到了它,结合积攒的一点知识,总算对其有了个大致了解。

先概述一下其用途。
从名称来看,zone, watermaker, 还有ok。
直观上来看,就是在某个zone上分配内存时,检查是否满足给定的watermark的要求。
zone就是memory zone,类型种类如下:
enum zone_type {
#ifdef CONFIG_ZONE_DMA
 /*
  * ZONE_DMA is used when there are devices that are not able
  * to do DMA to all of addressable memory (ZONE_NORMAL). Then we
  * carve out the portion of memory that is needed for these devices.
  * The range is arch specific.
  *
  * Some examples
  *
  * Architecture  Limit
  * ---------------------------
  * parisc, ia64, sparc <4G
  * s390   <2G
  * arm   Various
  * alpha  Unlimited or 0-16MB.
  *
  * i386, x86_64 and multiple other arches
  *    <16M.
  */
 ZONE_DMA,
#endif
#ifdef CONFIG_ZONE_DMA32
 /*
  * x86_64 needs two ZONE_DMAs because it supports devices that are
  * only able to do DMA to the lower 16M but also 32 bit devices that
  * can only do DMA areas below 4G.
  */
 ZONE_DMA32,
#endif
 /*
  * Normal addressable memory is in ZONE_NORMAL. DMA operations can be
  * performed on pages in ZONE_NORMAL if the DMA devices support
  * transfers to all addressable memory.
  */
 ZONE_NORMAL,
#ifdef CONFIG_HIGHMEM
 /*
  * A memory area that is only addressable by the kernel through
  * mapping portions into its own address space. This is for example
  * used by i386 to allow the kernel to address the memory beyond
  * 900MB. The kernel will set up special mappings (page
  * table entries on i386) for each page that the kernel needs to
  * access.
  */
 ZONE_HIGHMEM,
#endif
 ZONE_MOVABLE,
 __MAX_NR_ZONES
};

watermark的种类:
enum zone_watermarks {
 WMARK_MIN,    // 说明当前可以内存达到最低限了
 WMARK_LOW,    // 可用内存很少了,但还没到最低限,不是很紧急的情况,就不要占用内存了
 WMARK_HIGH,   // 剩余内存丰富,大家放心使用
 NR_WMARK
};

来看看__zone_watermark_ok的代码。
/*
 * Return true if free pages are above 'mark'. This takes into account the order
 * of the allocation.
 */
static bool __zone_watermark_ok(struct zone *z, int order, unsigned long mark,
        int classzone_idx, int alloc_flags, long free_pages)
{
 /* free_pages may go negative - that's OK */
 long min = mark;  // 既然是检查是否满足mark要求,先将最小值设置为mark
 int o;

 free_pages -= (1 << order) + 1;  // 检查谁满足mark要求?是free pages,并且是分配出去2^order个page之后的free pages. 为何要+1?
 if (alloc_flags & ALLOC_HIGH)  // 如果需求比较迫切,就放宽些限制
  min -= min / 2;
 if (alloc_flags & ALLOC_HARDER)  // 如果需求更加迫切,那就进一步放宽限制
  min -= min / 4;

 if (free_pages <= min + z->lowmem_reserve[classzone_idx])  // 如果free pages已经不大于保留内存和min之和,说明此次分配请求不满足wartmark要求

  return false;
 for (o = 0; o < order; o++) {  // 遍历buddy中比当前请求分配的order小的所有的order,依次检查free pages是否满足watermark要求。
  /* At the next order, this order's pages become unavailable */
  // 每个循环当中,先把当前order(从0至请求的order-1)的free pages从总free pages中减掉
  free_pages -= z->free_area[o].nr_free << o;
  
  // 然后将min,即mark,即判断标准作相应的缩小
  // linux中默认每次缩小一半,
  // android中引入了min_free_order_shift配置项,并且默认配置为4
  /* Require fewer higher order pages to be free */
  min >>= min_free_order_shift;
  
  // 比较处理后的free pages和min,看是否满足water mark要求
  if (free_pages <= min)
   return false;
 }
 return true;
}

函数中循环的目的可归结为:
依次循环,检查内存中是否有足够多的大块(即order比较高)空闲内存。
每次循环处理中,先把当前order的free page从总free pages中减掉,因为我们是看是否有足够多的大块内存。
当然,既然已经把free pages中的一部分已经划掉了,比较标准也应该相应放宽。
放宽多少,就是前面说的对min的右移处理。
举个例子,
如果请求分配的order是1,还有100个free pages,其中order 0的有96 pages,order 1的有4pages,处理后的min是16.
这样在第一轮循环中,free_pages即变为4,min假设右移了1位为8,这样判断下来不满足watermark要求。
如果将要求放宽,即将min_free_order_shift设置为4,这样第一轮循环中min变为1,free pages满足watermark要求。

 

抱歉!评论已关闭.