__zone_watermark_ok分析

__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要求。


————————————————
版权声明:本文为CSDN博主「njuitjf」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/njuitjf/article/details/17244651

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值