You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Linux系统中如何让已换出的file-backed可执行页保持不被重新加载

MADV_DONTNEED调用后页面非访问触发重映射的场景及解决方案

常见非CPU访问触发重映射的场景

  • 其他进程/内核组件主动读取目标进程内存:process_vm_readv()、ptrace()等系统调用,或者用户态读取/proc/[pid]/mem的操作,都会主动触发目标地址的缺页异常,无需目标进程自身访问内存地址。
    内核代码参考:对应逻辑位于mm/process_vm_access.c的process_vm_rw_core()函数,内部通过get_user_pages_remote()获取目标页面,触发缺页加载流程。
  • 内核后台线程的页表扫描操作:KSWAPD回收线程的反向映射扫描、KSM(内核同页合并)的重复页扫描、Cgroup内存统计扫描等后台操作,在遍历页表过程中可能触发页面加载,部分场景下还会更新页表访问标记,导致页面被误判为热页放回LRU链表。
    内核代码参考:KSM的扫描逻辑位于mm/ksm.c的scan_get_next_rmap_item()函数,缺页时会调用follow_page()触发页面加载。
  • 交换预读(Swap readahead)逻辑:当目标页面相邻的其他换出页被访问时,内核默认会触发交换预读,批量加载连续的多个换出页面,即使你没有访问这些额外页面。
    内核代码参考:对应逻辑位于mm/swap_state.c的swap_readahead()函数,默认预读窗口大小为交换集群大小的4倍,会连续加载相邻交换槽位的页面。
  • 同VMA区域的预读副作用:如果目标页面所在的VMA开启了预读,同区域其他页面触发缺页异常时,内核会顺带加载同区域的连续页面,导致被MADV_DONTNEED释放的页面被重新加载。
    内核代码参考:对应逻辑位于mm/memory.c的filemap_fault()函数,内部调用do_page_cache_ra()执行预读逻辑。

你之前的认知是正确的:MADV_DONTNEED调用确实会将目标匿名页从Active/Inactive LRU链表中移除并释放,对应代码位于mm/madvise.c的madvise_dontneed()函数,通过zap_page_range()清除页表项的同时,会将页面从LRU链表隔离后释放。

保持页面换出状态的可行方案

  • 优先调用madvise(MADV_RANDOM)标记目标内存区域,禁用该区域的文件、交换预读逻辑,避免相邻页面访问触发的批量加载。对应内核逻辑在mm/madvise.c的madvise_behavior()函数中,设置VM_RANDOM_READ标记后会将该区域预读窗口强制设为0。
  • Linux 5.4及以上内核可使用madvise(MADV_PAGEOUT)替代MADV_DONTNEED,该接口会直接将页面写入交换区并解除映射,不会触发后续的主动预读,换出效果比MADV_DONTNEED更稳定。
  • 如果是文件映射页,配合posix_fadvise(POSIX_FADV_DONTNEED)调用回收对应页缓存,避免页缓存命中导致页面被重新映射。

内容的提问来源于stack exchange,提问作者pcp

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 09:45:02