Linux下如何记录进程虚拟页访问?含Swap启用场景与实现方案咨询
跟踪启用Swap的应用程序页面访问次数的方案解析
一、修改mark_page_accessed的可行性
- 可行,但属于侵入式内核修改:
mark_page_accessed是内核中负责标记页面被访问的核心函数,服务于LRU等页置换算法。修改它确实可以插入统计逻辑,记录Swap页面的访问事件并关联到对应进程。 - 核心缺点:
- 需要修改内核源码、重新编译部署,维护成本极高,跨内核版本兼容性差。
- 需额外处理进程关联、Swap页面判定(如检查
page->flags中的PG_swapcache标记或swap_entry有效性),逻辑复杂易出错。 - 内核修改风险高,可能引入系统稳定性问题。
二、更优雅的内核态方案:eBPF
这是目前最推荐的非侵入式内核级方案,无需修改内核源码:
- 原理:通过
kprobe动态挂钩mark_page_accessed函数,或跟踪内核提供的page_referenced等相关tracepoint,在事件触发时提取进程ID、页面属性等信息。 - 实现步骤:
- 编写eBPF程序,挂钩目标函数后过滤出Swap相关页面(判断页面是否属于swap cache或已被swap out)。
- 用eBPF哈希表存储每个进程(PID)的Swap页面访问次数。
- 通过用户态程序(基于libbpf或bcc框架)读取哈希表中的统计数据,实时输出或持久化。
- 优势:无内核源码修改、动态加载卸载、性能损耗极低(eBPF程序运行在内核态但经过安全验证)、跨版本兼容性好。
三、用户态实现方案
用户态无法直接访问内核页面元数据,但可通过以下方式间接实现:
1. 结合perf工具与eBPF脚本
- 利用
perf的eBPF支持,编写用户态可加载的eBPF程序,跟踪Swap页面相关的缺页事件(如swap_in、swap_out)或页面访问触发的内核事件。 - 示例思路:用
perf record -e probe:mark_page_accessed --filter 'page->flags & PG_swapcache' -p <目标PID>,结合自定义脚本统计访问次数(需root权限)。
2. 周期性解析/proc文件系统
- 读取
/proc/<PID>/smaps文件,其中包含每个内存区域的Swap使用量,但无法直接获取访问次数。可结合周期性扫描+对比页面状态变化(如Swap页面的Referenced标记),间接估算访问频率。 - 缺点:实时性差、精度低,无法捕捉单次访问事件,仅能做粗略统计。
3. 应用层埋点(仅限可控应用)
如果目标应用是自主开发的,可在代码中添加内存访问的统计逻辑,结合mlock等工具区分Swap页面,但仅适用于自定义应用,通用性差。
总结
- 不推荐修改
mark_page_accessed,侵入性太强,维护成本高。 - 优先选择eBPF内核态方案,兼顾性能、准确性与灵活性。
- 用户态最优方案是基于perf的eBPF脚本,无需内核编译,仅需root权限即可实现较精准的统计。
内容的提问来源于stack exchange,提问作者s9mmy
相关产品推荐
相关产品推荐

