排查内存泄漏需系统化闭环:一、监控确认真实泄漏,区分内存增长与泄漏;二、三层筛查定位用户态、jvm或内核层;三、抓堆转储或内存快照分析引用链;四、修复后72小时验证曲线回归基线。

面试官问“排查内存泄漏的系统化流程”,不是想听你背命令,而是考察你有没有闭环思维、分层定位能力和生产实战意识。核心是:从现象到根因,层层收窄,不靠猜,靠证据。
一、监控发现:先确认是不是真泄漏
很多同学一上来就跑top或jstat,容易误判。首先要区分“内存增长”和“内存泄漏”:
- 看趋势是否单向不可逆——可用内存(MemAvailable 或 JVM 的 used heap)持续上升且无回落,尤其在业务低峰期仍在爬升,才是典型泄漏信号
- 排除缓存/缓冲区干扰——Linux 中 Cached、Buffers 属于可回收内存;Java 中 Young GC 后老年代仍缓慢上涨,才值得深挖
- 关键指标要定时采集——比如每5分钟记录
/proc/meminfo的 Slab、SUnreclaim,或 JVM 的 heap_used、non_heap_used、direct_memory
二、定位层级:快速判断泄漏发生在哪一层
内存泄漏可能出现在用户态堆、堆外、元空间、内核SLAB,甚至驱动层。用“三层筛查法”快速归因:
-
进程级:用
top -o %MEM或ps aux --sort=-%mem找出 RES 持续上涨的进程;再用pmap -x $PID | grep anon看匿名映射区(即堆+堆外)是否膨胀 -
JVM级(如为Java):结合
jstat -gc $PID观察 Full GC 频次与老年代占用率;若 MetaspaceUsed 持续涨,可能是类加载器泄漏;若 CompressedClassSpaceUsed 或 DirectMemory 上涨,指向堆外泄漏 -
内核级:当 top 看不到高内存进程,但
free显示可用内存极低、Slab却持续升高,尤其 SUnreclaim 不降,就要查/proc/slabinfo,用slabtop或grep找异常增长的 slab 缓存(如kmalloc-xxx、sock_inode_cache)
三、深度剖析:抓现场、看引用链
定位到具体进程或模块后,必须拿到“证据链”:
- Java 服务:配置
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dump/,或用jmap -dump:live,format=b,file=heap.hprof $PID主动导出;用 MAT 分析 Dominator Tree 和 Leak Suspects,重点追踪 GC Roots 到大对象的强引用路径 - C/C++ 服务:用
valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all ./app做运行时检测;长期运行服务可用gdb attach $PID+info proc mappings+dump memory结合 addr2line 定位分配点 - 内核模块:通过
slabinfo找出可疑缓存名(如nf_conntrack_*),再结合cat /sys/kernel/slab/<name>/alloc_calls</name>和cat /sys/kernel/slab/<name>/trace</name>(需开启 slab_debug)追源头
四、验证修复:闭环才算完成
改完代码不能只说“应该好了”,得用数据说话:
- 复现相同负载场景,对比修复前后内存曲线——要求 72小时稳定,无持续爬升趋势
- 对 Java 应用,观察 Full GC 后老年代水位是否回归基线;对 C 程序,用
cat /proc/$PID/status | grep VmRSS确认 RSS 不再单调增长 - 上线后加轻量级守护脚本:比如每10分钟检查
awk '/SUnreclaim/{print $2}' /proc/meminfo,超阈值自动告警











