文章说明:
-
Linux内核版本:5.0
-
架构:ARM64
-
参考资料及图片来源:《奔跑吧Linux内核》
-
Linux 5.0内核源码注释仓库地址:
zhangzihengya/LinuxSourceCode_v5.0_study (github.com)
外碎片化发生时,页面分配器还是会认为系统可以分配出内存,因为__zone_watermark_ok()
函数会返回TRUE,但是我们认为系统应该及时采取一些补救措施。在现有的内存管理机制下,我们能采取的补救措施就是提早唤醒kswapd内核线程以回收内存。另外,也提早唤醒kcompactd内核线程以做内存规整,这样有助于快速满足分配大块内存的需求,减少外碎片化。为此,Linux 5.0实现了—个临时增加水位(boost watermark)的功能。当发生挪用时,临时提高水位,并提前触发kswapd内核线程。
反碎片化优化的流程图如下所示:
该流程图中的相关说明如下:
-
Linux内核中的挪用规则:
// 此数组描述了当所需迁移类型的空闲列表耗尽时的挪用规则 static int fallbacks[MIGRATE_TYPES][4] = {[MIGRATE_UNMOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_MOVABLE, MIGRATE_TYPES },[MIGRATE_MOVABLE] = { MIGRATE_RECLAIMABLE, MIGRATE_UNMOVABLE, MIGRATE_TYPES },[MIGRATE_RECLAIMABLE] = { MIGRATE_UNMOVABLE, MIGRATE_MOVABLE, MIGRATE_TYPES }, #ifdef CONFIG_CMA[MIGRATE_CMA] = { MIGRATE_TYPES }, /* Never used */ #endif #ifdef CONFIG_MEMORY_ISOLATION[MIGRATE_ISOLATE] = { MIGRATE_TYPES }, /* Never used */ #endif };
-
__rmqueue_fallback()->steal_suitable_fallback()->boost_watermark()
-
在临时提高水位后,那什么时候恢复到正常的水位呢?
Kswapd 内核线程被唤醒之后,它会根据扫描优先级扫描LRU链表和尝试回收页面。当发现zone处于平衡状态或者一轮扫描完成之后,它会把这个临时提高的水位取消,并且唤醒 kcompactd内核线程,让它以页块大小为目标尝试进行内存规整。
// 回收页面的主要函数 static int balance_pgdat(pg_data_t *pgdat, int order, int classzone_idx) {... out:if (boosted) {...for (i = 0; i <= classzone_idx; i++) {...zone->watermark_boost -= min(zone->watermark_boost, zone_boosts[i]);...}// 若设置了 boosted,则唤醒 kcompactd 内核线程wakeup_kcompactd(pgdat, pageblock_order, classzone_idx);}...// 返回已经回收的页面数量return sc.order; }