内存泄漏的典型表现与初步判断
Linux服务器运行一段时间后可用内存持续下降,最终触发OOM Killer杀掉进程,这是内存泄漏最典型的症状。通过free -h和cat /proc/meminfo可以快速确认内存消耗趋势,但定位具体哪个进程泄漏需要更细致的工具链配合。
常见误区:看到buff/cache数值高就认为是内存泄漏。Linux内核会将空闲内存用于磁盘缓存,这部分内存在需要时可立即释放,属于正常行为。真正需要关注的是used列的持续增长。
使用smem和top定位泄漏进程
第一步是确认哪个进程在持续消耗内存。smem工具比top更适合这个场景,因为它能显示USS(独占内存)、PSS(按比例分摊内存)和RSS(驻留内存)三个维度。
安装smem:
yum install smem # CentOS/RHEL
apt install smem # Ubuntu/Debian
按USS排序查看内存占用前20的进程:
smem -t -k -s uss | tail -n +2 | head -20
定期采集数据建立基线,对比不同时间点的USS变化:
while true; do
echo "$(date)" >> /tmp/mem_log.txt
smem -t -k -s uss | head -15 >> /tmp/mem_log.txt
sleep 300
done
如果某个进程的USS持续增长且不回落,基本可以确认该进程存在内存泄漏。
用Valgrind和AddressSanitizer精确定位
确认了泄漏进程后,需要定位到代码层面。对于C/C++程序,Valgrind的memcheck工具是经典方案:
valgrind --leak-check=full --show-leak-kinds=all \
--track-origins=yes --verbose \
--log-file=valgrind_out.txt \
/path/to/your_program
Valgrind的缺点是会使程序运行速度降低10-50倍,生产环境不适用。更轻量的方案是GCC/Clang内置的AddressSanitizer:
# 编译时添加ASan选项
gcc -fsanitize=address -fno-omit-frame-pointer -g leak_program.c -o leak_program
# 运行时设置泄漏检测
ASAN_OPTIONS=detect_leaks=1 ./leak_program
ASan的性能开销通常在2倍以内,可以在预发布环境运行。程序退出时会输出泄漏报告,包含分配位置和调用栈。
Java应用的堆内存泄漏排查
Java应用的内存泄漏排查思路不同。使用jmap导出堆转储:
# 获取Java进程PID
jps -l
# 导出堆转储
jmap -dump:format=b,file=heapdump.hprof <pid>
用jhat或MAT(Memory Analyzer Tool)分析堆转储文件。MAT的Dominator Tree视图能快速定位占堆内存最大的对象集合。
在线排查可以用Arthas,无需重启JVM:
# 启动Arthas
java -jar arthas-boot.jar
# 监控内存分配
dashboard
# 查看对象统计
heapdump --live /tmp/heap_live.hprof
Go程序的内存泄漏分析
Go程序使用pprof工具链排查内存泄漏:
import _ "net/http/pprof"
go func() {
http.ListenAndServe("localhost:6060", nil)
}()
采集内存profile并分析:
# 采集30秒的内存分配profile
go tool pprof -http=:8080 http://localhost:6060/debug/pprof/heap
pprof的火焰图和top视图会显示哪些函数分配了最多内存。常见Go内存泄漏原因包括:goroutine未退出、time.Ticker未Stop、闭包捕获大对象。
修复后的验证与监控
修复内存泄漏后,需要在相同负载下进行至少72小时的稳定性测试,确认内存使用曲线不再持续上升。部署到生产环境后,配置告警规则:
# Prometheus告警规则示例
- alert: MemoryLeakSuspected
expr: process_resident_memory_bytes{job="target-service"} > 8*1024*1024*1024
for: 30m
labels:
severity: warning
annotations:
summary: "Process memory usage exceeds 8GB"
内存泄漏排查没有银弹,核心是建立基线、持续监控、分层定位。从系统级工具确认问题进程,到语言级工具定位代码行,每一步都需要耐心和经验。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linux-fu-wu-qi-nei-cun-xie-lou-pai-cha-shi-zhan-cong-ding/