Linux 内存管理硬核揭秘:kswapd 与内存 compact 的本质剖析


🎥 相关博文对应 :B站精讲视频



Linux 内存管理硬核揭秘:kswapd 与内存 compact 的本质剖析

内核内存紧张时,谁在幕后调度内存?分配大块内存失败怎么处理?kswapdcompact 有什么不同?本文为你一次讲透!


在这里插入图片描述

一、你遇到过这些问题吗?

  1. 什么是 kswapd?它和 direct reclaim 的关系是什么?
  2. kswapd 主要做什么?内存回收是主动还是被动?
  3. 什么是内存碎片?为什么需要 compact?
  4. compact 机制和 kswapd 机制的区别?它们能解决什么问题?
  5. 如果大块内存分配(order>0)失败,内核会如何补救?
  6. 怎么通过内核参数和调试工具监控和分析 kswapd/compact 行为?
  7. 在代码里 kswapd、compact 分别是怎么被调度、调用的?主流程是啥?

二、内核内存管理:宏观结构速览

内存分配相关的核心流程与“幕后角色”:

  • Page Allocator(伙伴系统):核心内存分配器,管理物理页框,order 代表分配的连续页数量(2^order)。
  • kswapd:内存回收“守护神”,负责定期回收不再使用的页,维护系统内存水位。
  • Direct Reclaim:应用进程自身分配内存失败时,自己直接参与内存回收。
  • Memory Compact(内存压缩):专门将内存碎片合并成大块,提升高阶页分配成功率。
  • OOM Killer:最后防线,内存极度紧张时杀死进程释放内存。

三、kswapd:内存回收守护者

1. kswapd 的核心作用

  • 监控内存水位线(如 /proc/meminfo 中的 LowFree 等)。
  • 自动回收不再被使用的页(如页面缓存、匿名页、slab 缓存等),以确保系统运行稳定。
  • 只做回收,不做碎片整理。
  • 唤醒机制: 只要某个 zone 的可用页低于 water mark(如 WMARK_MIN),伙伴系统就唤醒 kswapd 线程。

2. kswapd 的主要流程

  • 持续循环(线程),每次回收尝试满足各 zone 的水位要求。
  • 典型路径(简化):
// mm/vmscan.c
int kswapd(void *p) {
    ...
    for (;;) {
        try_to_free_pages()
        // 1. 选择 zone
        // 2. 判断是否达到水位
        // 3. 选中 victim page,回收
    }
}
  • 回收类型:

    • 页面缓存(page cache)
    • 匿名页(anonymous pages)
    • slab 缓存
  • 触发入口:

    • 在伙伴系统中,__alloc_pages_slowpath() 发现低于水位,wakeup_kswapd() 立即唤醒 kswapd

3. kswapd 和 direct reclaim 区别

机制触发场景行为作用对象
kswapd内存低于水位线后台异步回收整个系统的内存
direct reclaim分配内存时直接失败当前进程同步回收只为当前进程服务

四、Memory Compact:内存碎片终结者

1. 为什么要有 compact?

  • 碎片问题:随着系统运行,虽然有很多“零散”的空页,但无法满足高阶(order>0)连续页的分配需求,比如大页分配、设备 DMA、hugepage 等。

  • compact 的目的: 把分散的空闲页“合并”成更大块的连续空闲内存区域。

2. compact 的工作机制

  • 主动合并:遍历内存区域,将未使用的物理页“向一边搬运”,生成连续空间。

  • 调用时机

    • 高阶分配失败后自动触发(如分配 order=9 大页失败)。
    • 系统后台也会定期尝试。
    • 手动触发(如 echo 1 > /proc/sys/vm/compact_memory)。

3. 典型流程

// mm/compaction.c
int compact_zone(zone, ...) {
    // 1. 从低地址开始,找到空闲页
    // 2. 从高地址找出在用页
    // 3. 把在用页迁移到空闲页上
    // 4. 形成大块连续空闲空间
}
  • 核心函数:

    • try_to_compact_pages()
    • compact_zone()
    • migrate_pages()

4. kcompactd 内核线程

  • kcompactd 专门负责在后台做碎片整理,逻辑类似 kswapd,但目标是碎片合并而不是回收。
  • 唤醒机制类似:伙伴系统分配高阶页失败时唤醒。

五、调用关系与联动机制

1. 内存分配主流程

  1. 应用或内核模块申请内存(如 kmalloc())。
  2. 伙伴系统先尝试快速分配(__alloc_pages_fast())。
  3. 如果失败,则进入慢速分配路径(__alloc_pages_slowpath())。
  4. 先唤醒 kswapd,试图回收;如仍然失败,再 direct reclaim(进程自己回收)。
  5. 如果发现碎片严重,尝试 compact,调用 try_to_compact_pages()
  6. 如果依然失败,触发 OOM Killer。

2. 代码调用链(高阶分配失败为例)

// mm/page_alloc.c
__alloc_pages_slowpath()
    -> wakeup_kswapd()
    -> try_to_free_pages()
    -> try_to_compact_pages()
    -> OOM_killer()

六、典型结构与数据流示意

1. 结构对比表

名称类型线程/任务作用/定位是否主动/被动
kswapd内核线程每个 zone自动回收内存,保持水位主动(后台)
kcompactd内核线程每个 zone合并空闲页,消除碎片主动(后台)
direct reclaim回调/流程当前进程回收,紧急场合被动(前台)
compact回调/流程分配大块内存时合并碎片被动/主动均有

2. 主流程图(简化)

          应用/内核请求分配内存
                   |
         -----------------------
        | 伙伴系统快速分配      |
        -----------------------
           |    失败
           v
     __alloc_pages_slowpath
        |        |         |
  唤醒kswapd  回收页  尝试compact
                   |         |
               分配成功?   否
                       |
                   OOM killer

七、调试与监控方法

  • /proc/buddyinfo 查看各阶空闲页分布,判断碎片。
  • /proc/vmstat 关注 pgscan_kswapd*compact* 字段。
  • tracepoint/ftrace 监控 mm_vmscan_、mm_compaction_ 事件。
  • dmesgprintk 可见 kswapd、compact 相关日志。

八、常见面试/高频开发问题

1. 什么场景下只回收而不 compact?反之呢?

  • 回收:普通分配或内存紧张,回收能立即释放就行。
  • compact:分配高阶页(大块内存、hugepage、DMA buffer)时,只有碎片严重才 compact。

2. kswapd 会导致性能下降吗?如何优化?

  • 频繁唤醒会消耗系统资源。合理调整水位线参数(/proc/sys/vm/min_free_kbytes),避免频繁回收。

3. 怎么判断是内存不足还是碎片问题?

  • buddyinfo 各阶页面充足但高阶很少,且 free 总量充裕→碎片。
  • 总量少所有阶都低→真正内存不足。

4. 分配大块内存一定会失败吗?

  • 如果高阶页不够且 compact 也合并不出,则失败。否则只要物理内存有空闲,是有希望的。

5. 如何手动触发 compact?

  • echo 1 > /proc/sys/vm/compact_memory

九、总结提炼

  • kswapd:专注后台回收,维持系统水位,是内存的“看门人”。
  • compact/kcompactd:专注合并碎片,保障高阶页分配成功,是“大块内存”的“铺路者”。
  • 两者各司其职,配合 direct reclaim 和 OOM Killer,构成了 Linux 高效而健壮的内存分配防线。

十、相关核心问题(附标准答案)

  1. kswapd 的触发机制与主要作用?

    • 答:当某 zone 低于水位线时被唤醒,负责回收页缓存、匿名页等,保障分配不阻塞。
  2. 什么是 compact,它和 kswapd 有什么区别?

    • 答:compact 合并碎片,生成高阶连续页。kswapd 回收内存但不负责碎片合并。
  3. 高阶分配失败时的内核处理路径?

    • 答:先回收(kswapd/direct reclaim),再 compact(kcompactd),都失败则 OOM。
  4. 怎么区分系统内存紧张和碎片化问题?

    • 答:通过 /proc/buddyinfo 分析各阶空闲页分布,判断总量与连续性。
  5. 如何手动触发 compact 或 kswapd?

    • 答:compact: echo 1 > /proc/sys/vm/compact_memory;kswapd 通常自动管理。


🎥 相关博文对应 :B站精讲视频


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值