内存泄漏的典型表现
Linux服务器运行一段时间后可用内存持续下降,OOM Killer开始随机终止进程,dmesg日志出现Out of memory: Killed process记录——这是内存泄漏最直接的信号。与正常内存使用不同,泄漏的特征是内存占用只增不减,即使业务低峰期也不会回落。
服务器运维中,内存泄漏是最难定位的问题之一,因为泄漏可能发生在应用层、中间件层、内核层任意位置。下面的排查流程覆盖从快速定位到根因分析的完整链路。
第一步:确认泄漏对象
使用以下命令快速锁定内存占用异常的进程:
# 按内存占用排序,取前20
ps aux --sort=-%mem | head -21
# 更直观的方式:使用smem(需安装)
smem -t -k -s rss | tail -20
# 关注进程的RSS增长趋势
while true; do
echo "$(date) $(ps -p $PID -o rss=)"
sleep 60
done > mem_trend.log
记录目标进程的PID,持续观察RSS变化。如果RSS呈单调递增且不回落,确认存在泄漏。
第二步:区分进程内存与系统内存
服务器内存泄漏不一定来自用户进程。用free和/proc/meminfo分析整体分布:
# 查看内存分布
free -m
cat /proc/meminfo | grep -E "MemTotal|MemFree|MemAvailable|Buffers|Cached|Slab|KernelStack|PageTables|Shmem|AnonPages"
# 内核Slab缓存占用(常见泄漏源)
slabtop -o -s d | head -20
重点关注以下指标:
AnonPages持续增长表明应用层泄漏
Slab持续增长表明内核对象泄漏
Shmem异常增长表明共享内存未释放(常见于PostgreSQL、Oracle)
第三步:应用层泄漏深入分析
确认泄漏进程后,根据语言和运行时选择分析工具:
Java应用:使用jmap生成堆转储,用MAT或VisualVM分析
# 生成堆转储(不影响运行)
jmap -dump:live,format=b,file=heapdump.hprof $PID
# 查看活跃对象统计
jmap -histo:live $PID | head -30
# GC情况(判断是否为内存泄漏还是GC不及时)
jstat -gcutil $PID 1000 10
Go应用:使用pprof分析内存分配
# 如果应用集成了pprof
curl http://localhost:6060/debug/pprof/heap > heap.prof
go tool pprof -http=:8080 heap.prof
# 运行时无需pprof集成
go tool pprof http://localhost:6060/debug/pprof/heap
Python应用:使用tracemalloc或objgraph
import tracemalloc
import gc
tracemalloc.start()
# ... 运行业务代码 ...
snapshot = tracemalloc.take_snapshot()
top_stats = snapshot.statistics("lineno")
for stat in top_stats[:20]:
print(stat)
第四步:内核层泄漏排查
当Slab占用持续增长且无法回收,需排查内核模块:
# 查看各Slab对象占用
cat /proc/slabinfo | sort -k4 -n -r | head -20
# 跟踪内核内存分配(需debug内核)
echo 1 > /sys/kernel/debug/tracing/events/kmem/kmalloc/enable
echo 1 > /sys/kernel/debug/tracing/events/kmem/kfree/enable
cat /sys/kernel/debug/tracing/trace_pipe > kmem_trace.log
# 检查已加载模块是否有已知内存泄漏问题
modinfo -d module_name
# 或查看dmesg中内核警告
dmesg | grep -i "memory|leak|oom|warning"
第五步:临时止血与长期修复
临时止血措施:
1. 调整OOM策略:保护关键进程不被杀
# 设置关键进程的OOM评分(-1000表示永不杀)
echo -1000 > /proc/$PID/oom_score_adj
# 或修改系统级OOM行为
echo "vm.overcommit_memory=2" >> /etc/sysctl.conf
sysctl -p
2. 定期重启泄漏进程:作为临时方案,配置定时任务
# crontab: 每天凌晨3点重启泄漏的Java应用
0 3 * * * /bin/systemctl restart app-name
3. 增加Swap空间:争取更多排查时间
fallocate -l 8G /swapfile
chmod 600 /swapfile
mkswap /swapfile
swapon /swapfile
长期修复的核心是定位泄漏代码并修复,不是靠重启或扩容绕过问题。当应用层工具无法定位时,需要用Valgrind(C/C++)、AddressSanitizer等工具在测试环境复现并精确定位。
服务器内存故障排查的流程总结
内存泄漏排查遵循「先定进程、再分层次、后抓根因」的原则。先用ps/smem定位异常进程,再用free/meminfo区分应用与内核,然后用语言对应的profiling工具深入分析。内核泄漏需检查Slab和模块日志。运维人员在日常巡检中应建立内存基线监控,在泄漏初期就能发现异常趋势,避免等到OOM Killer触发才响应。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/linux-fu-wu-qi-nei-cun-xie-lou-pai-cha-shi-zhan-cong-xian/