重要的数据结构

/** Determines how hard direct compaction should try to succeed.* Lower value means higher priority, analogically to reclaim priority.*/
enum compact_priority {COMPACT_PRIO_SYNC_FULL,MIN_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_FULL,COMPACT_PRIO_SYNC_LIGHT,MIN_COMPACT_COSTLY_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,DEF_COMPACT_PRIORITY = COMPACT_PRIO_SYNC_LIGHT,COMPACT_PRIO_ASYNC,INIT_COMPACT_PRIORITY = COMPACT_PRIO_ASYNC
};

这个结构是compaction的优先级

  • COMPACT_PRIO_SYNC_FULL:完全同步模式,允许祖塞,允许将脏页写回到存储设备上,直到等待完成
  • COMPACT_PRIO_SYNC_LIGHT: 轻量级同步模式,允许绝大多数祖塞,但是不允许将脏页写回到存储设备上,因为等待时间比较长
  • COMPACT_PRIO_ASYNC: 异步模式,不允许祖塞
  • 优先级关系:  COMPACT_PRIO_SYNC_FULL >  COMPACT_PRIO_SYNC_LIGHT > COMPACT_PRIO_ASYNC
  • compation对应的成本:COMPACT_PRIO_SYNC_FULL >  COMPACT_PRIO_SYNC_LIGHT > COMPACT_PRIO_ASYNC
  • 完全同步成功率最高

再来看下compaction的成功是否的状态

/* Return values for compact_zone() and try_to_compact_pages() */
/* When adding new states, please adjust include/trace/events/compaction.h */
enum compact_result {/* For more detailed tracepoint output - internal to compaction */COMPACT_NOT_SUITABLE_ZONE,/** compaction didn't start as it was not possible or direct reclaim* was more suitable*/COMPACT_SKIPPED,/* compaction didn't start as it was deferred due to past failures */COMPACT_DEFERRED,/* compaction not active last round */COMPACT_INACTIVE = COMPACT_DEFERRED,/* For more detailed tracepoint output - internal to compaction */COMPACT_NO_SUITABLE_PAGE,/* compaction should continue to another pageblock */COMPACT_CONTINUE,/** The full zone was compacted scanned but wasn't successfull to compact* suitable pages.*/COMPACT_COMPLETE,/** direct compaction has scanned part of the zone but wasn't successfull* to compact suitable pages.*/COMPACT_PARTIAL_SKIPPED,/* compaction terminated prematurely due to lock contentions */COMPACT_CONTENDED,/** direct compaction terminated after concluding that the allocation* should now succeed*/COMPACT_SUCCESS,
};
  • COMPACT_SKIPPED: 跳过此zone,可能此zone不适合
  • COMPACT_DEFERRED:此zone不能开始,是由于此zone最近失败过
  • COMPACT_CONTINUE:继续尝试做page compaction
  • COMPACT_COMPLETE:  对整个zone扫描已经完成,但是没有规整出合适的页
  • COMPACT_PARTIAL_SKIPPED: 扫描了部分的zone,但是没有找到合适的页
  • COMPACT_SUCCESS:规整成功,并且合并出空闲的页

fragmentation index(碎片指数)

当我们申请内存失败的时候有两种原因:

  • 内存不够
  • 内存碎片太多

那怎么确定到底是什么原因导致分配失败的,所以就出现了碎片指数。取值范围[0  1000]

  • 碎片指数趋近于0,说明申请内存失败原因是由于内存不足
  • 碎片指数趋近于1000,说明申请内存失败原因是内存碎片太多

当然了内核同时提供了一个值,来控制碎片指数。int sysctl_extfrag_threshold = 500; 默认值是500

root:/ # cat /proc/sys/vm/extfrag_threshold
500

这个值默认是500的,如果设置太大,则每次申请内存失败,都会归结为内存不够。如果申请太小,则page compaction就会太频繁,系统负载就会增加

判断一个zone是否合适做page compaction

enum compact_result compaction_suitable(struct zone *zone, int order,unsigned int alloc_flags,int classzone_idx)
{enum compact_result ret;int fragindex;ret = __compaction_suitable(zone, order, alloc_flags, classzone_idx,zone_page_state(zone, NR_FREE_PAGES));/** fragmentation index determines if allocation failures are due to* low memory or external fragmentation** index of -1000 would imply allocations might succeed depending on* watermarks, but we already failed the high-order watermark check* index towards 0 implies failure is due to lack of memory* index towards 1000 implies failure is due to fragmentation** Only compact if a failure would be due to fragmentation. Also* ignore fragindex for non-costly orders where the alternative to* a successful reclaim/compaction is OOM. Fragindex and the* vm.extfrag_threshold sysctl is meant as a heuristic to prevent* excessive compaction for costly orders, but it should not be at the* expense of system stability.*/if (ret == COMPACT_CONTINUE && (order > PAGE_ALLOC_COSTLY_ORDER)) {fragindex = fragmentation_index(zone, order);if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)ret = COMPACT_NOT_SUITABLE_ZONE;}trace_mm_compaction_suitable(zone, order, ret);if (ret == COMPACT_NOT_SUITABLE_ZONE)ret = COMPACT_SKIPPED;return ret;
}
  • __compaction_suitable 此函数主要用来判断此zone是否合适做page compaction
  • 如果此函数返回的是COMPACT_CONTINUE,而且order是昂贵的分配,则就会去获取碎片指数,如果碎片指数在[0-500]之间,则此zone不适合做page compaction
  • 最终返回的结果是跳过此zone=COMPACT_SKIPPED
static enum compact_result __compaction_suitable(struct zone *zone, int order,unsigned int alloc_flags,int classzone_idx,unsigned long wmark_target)
{unsigned long watermark;if (is_via_compact_memory(order))return COMPACT_CONTINUE;watermark = wmark_pages(zone, alloc_flags & ALLOC_WMARK_MASK);/** If watermarks for high-order allocation are already met, there* should be no need for compaction at all.*/if (zone_watermark_ok(zone, order, watermark, classzone_idx,alloc_flags))return COMPACT_SUCCESS;watermark = (order > PAGE_ALLOC_COSTLY_ORDER) ?low_wmark_pages(zone) : min_wmark_pages(zone);watermark += compact_gap(order);if (!__zone_watermark_ok(zone, 0, watermark, classzone_idx,ALLOC_CMA, wmark_target))return COMPACT_SKIPPED;return COMPACT_CONTINUE;
}
  • 如果是通过设置/proc/sys/vm/compaction_memory,则order=-1, 则规整继续
  • 如果不是通过设置compaction_memory节点的,则先获取当前zone的水位
  • 通过zone_watermark_ok函数可以判断当前zone的内存很足够,(空闲页面-申请页面 >=水位)则返回COMPACT_SUCCESS说明此zone不需要做内存规整
  • 根据当前zone是否是昂贵的order,如果是昂贵的order,则获取low水位的值,否则获取min水位的值
  • 如果(空闲页面-申请页面)>= watetmark + 2*order的页,则此zone需要做内存规整

内存碎片整理推迟

为什么需要内存碎片整理推迟?

如果上次内存碎片整理失败,当下一次进行内存碎片整理的时候和上一次很近,如果不推迟的话有可能还会失败,白白的增加系统的负载。所以当下一次进行内存碎片整理的时候,则需要推迟。在结构体zone中就定义了推迟整理的几个字段

struct zone {
#ifdef CONFIG_COMPACTION/** On compaction failure, 1<<compact_defer_shift compactions* are skipped before trying again. The number attempted since* last failure is tracked with compact_considered.*/unsigned int        compact_considered;unsigned int        compact_defer_shift;int         compact_order_failed;
#endif
}
  • compact_considered代表推迟的次数
  • compact_defer_shift是推迟的次数以2的底数
  • compact_order_failed记录碎片整理是分配的order数

当做碎片整理失败的时候,会调用到此函数

/* Do not skip compaction more than 64 times */
#define COMPACT_MAX_DEFER_SHIFT 6void defer_compaction(struct zone *zone, int order)
{zone->compact_considered = 0;zone->compact_defer_shift++;if (order < zone->compact_order_failed)zone->compact_order_failed = order;if (zone->compact_defer_shift > COMPACT_MAX_DEFER_SHIFT)zone->compact_defer_shift = COMPACT_MAX_DEFER_SHIFT;
}
  • 将compact_defer_shift加1, 如果compact_defer_shift的值大于6,则设置为6
  • 说明最大最迟次数为64次,当超过64次之后,则不能推迟了。
  • 如果申请的order小于compact_order_failed, 则设置compact_order_failed=order

当做碎片整理成功的时候,则会调用到compaction_defer_reset函数

void compaction_defer_reset(struct zone *zone, int order, bool alloc_success)
{if (alloc_success) {zone->compact_considered = 0;zone->compact_defer_shift = 0;}if (order >= zone->compact_order_failed)zone->compact_order_failed = order + 1;
}
  • 当分配成功后,会将compact_defer_shift设置为0
  • 同时如果order大于等于compact_order_failed时,则将compact_order_failed设置为order+1

如何确定本次碎片整理是否结束

  • 当迁移扫描器和空闲扫描器相遇的时候,则怎么本次碎片整理结束
  • 当迁移扫描器和空闲扫描器没有相遇,但是从此zone中的根据迁移类型可以从freelist中获取一个大得空闲的页,或者从备用的迁移类型中可以获取一个大的空闲的页,则认为本次碎片整理结束
static enum compact_result __compact_finished(struct compact_control *cc)
{if (compact_scanners_met(cc)) {                          //相遇了/* Let the next compaction start anew. */reset_cached_positions(cc->zone);/** Mark that the PG_migrate_skip information should be cleared* by kswapd when it goes to sleep. kcompactd does not set the* flag itself as the decision to be clear should be directly* based on an allocation request.*/if (cc->direct_compaction)cc->zone->compact_blockskip_flush = true;if (cc->whole_zone)return COMPACT_COMPLETE;elsereturn COMPACT_PARTIAL_SKIPPED;}for (order = cc->order; order < MAX_ORDER; order++) {struct free_area *area = &cc->zone->free_area[order];bool can_steal;/* Job done if page is free of the right migratetype */          //有空闲内存了,返回SUCCESSif (!list_empty(&area->free_list[migratetype]))return COMPACT_SUCCESS;#ifdef CONFIG_CMA/* MIGRATE_MOVABLE can fallback on MIGRATE_CMA */if (migratetype == MIGRATE_MOVABLE &&!list_empty(&area->free_list[MIGRATE_CMA]))return COMPACT_SUCCESS;
#endifif (find_suitable_fallback(area, order, migratetype,            //从备用迁移类型中分配成功了。true, &can_steal, cc->order) != -1) {/* movable pages are OK in any pageblock */if (migratetype == MIGRATE_MOVABLE)return COMPACT_SUCCESS;
}

page compaction代码分析之一相关推荐

  1. 【Linux 内核 内存管理】物理分配页 ⑨ ( __alloc_pages_slowpath 慢速路径调用函数源码分析 | retry 标号代码分析 )

    文章目录 一.retry 标号代码分析 二.retry 标号完整代码 在 [Linux 内核 内存管理]物理分配页 ② ( __alloc_pages_nodemask 函数参数分析 | __allo ...

  2. kernel 3.10代码分析--KVM相关--虚拟机创建\VCPU创建\虚拟机运行

    分三部分:一是KVM虚拟机创建.二是VCPU创建.三是KVM虚拟机运行 第一部分: 1.基本原理 如之前分析,kvm虚拟机通过对/dev/kvm字符设备的ioctl的System指令KVM_CREAT ...

  3. TensorFlow-CIFAR10 CNN代码分析

    CIFAR 代码组织 代码分析 cifar10_trainpy cifar10py cifar10_evalpy Reference 根据TensorFlow 1.2.1,改了官方版本的报错. CIF ...

  4. c++代码健壮性_复活Navex-使用图查询进行代码分析(上)

    从了解到修复 Navex, 其中花了一年多, 从对自动化代码审计一无所知到学习PL/Static Analysis, 翻阅十几年前的文档, 补全Gremlin Step, 理解AST, CFG, DD ...

  5. 使用VS2010代码分析功能增强ASP.NET应“.NET研究”用程序安全

    任何从事ASP.NET开发的人都不得不承认,在其职业生涯中曾经遇到过应用程序安全问题,开发人员常常被迫尽快交付代码,平台的复杂性和各种配置选项让应用程序的安全总达不到预期,此外,调试和生产环境的配置要 ...

  6. linux内存映射起始地址,内存初始化代码分析(三):创建系统内存地址映射

    内存初始化代码分析(三):创建系统内存地址映射 作者:linuxer 发布于:2016-11-24 12:08 分类:内存管理 一.前言 经过内存初始化代码分析(一)和内存初始化代码分析(二)的过渡, ...

  7. SRS 代码分析【mpeg-ts解析】

    SRS 代码分析[mpeg-ts解析] 1.SrsTsContext的decode接口定义如下: int SrsTsContext::decode(SrsBuffer* stream, ISrsTsH ...

  8. arm linux kernel 从入口到start_kernel 的代码分析

    Linux系统启动过程分析(主要是加载内核前的动作) 经过对Linux系统有了一定了解和熟悉后,想对其更深层次的东西做进一步探究.这当中就包括系统的启动流程.文件系统的组成结构.基于动态库和静态库的程 ...

  9. SRS 代码分析【HLS切片】

    转载:http://blog.csdn.net/ManagerUser/article/details/76087151 一.前言         SRS流媒体服务器支持rtmp协议,但是rtmp协议 ...

  10. 20189200余超 2018-2019-2 移动平台应用开发实践作项目代码分析

    20189200余超 2018-2019-2 移动平台应用开发实践作项目代码分析 项目名称 小说阅读器 项目功能 注册登录 用户信息.用户密码.用户图像修改 书籍分类 书架 书籍搜索(作者名或书籍名) ...

最新文章

  1. day04 JDBC java数据库连接
  2. 微信开放JS-SDK,助力网页开发[转自微信官方]
  3. 英国推6.5亿英镑网络安全战略 强化安全屏障
  4. [转]Linux文件搜索
  5. 使用大脑活动反馈的刺激技术自动化治疗脑部疾病
  6. 倒计时2天!AI大咖云集、30场技术公开课,还有乐队... 年度最有意思的AI开发者活动来了!...
  7. FD.io/VPP — VPP 的配置与运行
  8. PspCidTable 完全解读
  9. CTFshow 反序列化 web255
  10. 输入分钟输出小时python_输出键,值对如何使1小时内的时间在使用Python的MapReduce中的reducer中结束?...
  11. php 年月日 中文,php Date()函数输出中文年月日时分秒_PHP教程
  12. C#LeetCode刷题-哈希表
  13. 森林图怎么分析_新疆森林消防总队特勤大队:“火焰蓝”备战春防,我们时刻准备着!...
  14. 苹果 SwiftUI 踢馆谷歌 Flutter!
  15. linux apache安全,基于Linux平台的Web安全技术研究——Apache安全.doc
  16. cfiledialog对话框大小_CFileDialog类 通用对话框
  17. 27、一个扒网站软件——teleport ultra(静态页面)
  18. Scene Graph Generation by Iterative Message Passing
  19. 这几款视频语音转文字软件你值得拥有
  20. 批量打印--不展现直接后台打印

热门文章

  1. flex弹性布局学习总结
  2. 使用Visual Studio进行单元测试-Part4
  3. 转:运行yum报错Error: Cannot retrieve metalink for reposit
  4. CCV 调试 (一)
  5. autohotkey -- AHK 替换 4 为 $ 方便脚本编写
  6. android can为啥能发收不到数据_大数据显示:报读MBA已是未来竞争力提升的必然趋势...
  7. 3.JUC线程高级-同步容器 ConcurrentHashMap
  8. 洛谷——P1744 采购特价商品
  9. R语言领跑 大数据岗位霸占IT薪酬榜单
  10. 仿微信选项卡主页面创建