内存泄漏的快速定位技巧

内存泄漏的快速定位技巧

内存泄漏是后台服务最常见的问题之一。我在生产环境中遇到过各种内存泄漏场景:Java 堆外内存泄漏、Go 的 goroutine 泄漏、C++的野指针问题等。经过多次实战,我总结了一套快速定位内存泄漏的方法。

Java 应用内存泄漏排查

堆内存泄漏

1
2
3
4
5
6
7
8
9
10
# 1. 生成heap dump
jmap -dump:format=b,file=heap.dump <pid>

# 2. 使用MAT分析
# 关注 Dominator Tree 中的大对象
# 查看 Leak Suspects 自动分析结果

# 3. 常见泄漏点检查
jmap -histo <pid> | head -20
# 重点关注实例数量异常的类

堆外内存泄漏

1
2
3
4
5
6
# 使用pmap查看进程内存映射
pmap -d <pid> | sort -k2 -nr | head -20

# 如果发现大量匿名映射,可能是DirectByteBuffer泄漏
# 启动参数添加:-XX:MaxDirectMemorySize=1G
# 监控指标:java.nio:type=BufferPool,name=direct

实战案例:某微服务运行 3 天后 OOM,堆内存正常但 RSS 持续增长。通过 pmap 发现大量 64MB 的匿名映射,最终定位到 Netty 的 DirectBuffer 未及时释放,通过调整-XX:MaxDirectMemorySize 和优化连接池解决。

Go 程序内存泄漏排查

Goroutine 泄漏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 监控goroutine数量
func monitorGoroutines() {
ticker := time.NewTicker(30 * time.Second)
for {
select {
case <-ticker.C:
count := runtime.NumGoroutine()
log.Printf("Current goroutines: %d", count)
}
}
}

// 使用pprof分析
import _ "net/http/pprof"

// 访问 http://localhost:6060/debug/pprof/goroutine?debug=1
// 查看goroutine调用栈

内存分配分析

1
2
3
4
5
6
7
8
9
10
11
# 1. 生成内存profile
go tool pprof http://localhost:6060/debug/pprof/heap

# 2. 查看top消耗
(pprof) top10

# 3. 查看调用图
(pprof) web

# 4. 分析具体函数
(pprof) list funcName

常见 Go 内存泄漏模式

  • Channel 未关闭导致 goroutine 阻塞
  • Timer 未 stop 导致资源未释放
  • 全局 map 持续增长未清理

快速排查工具集

系统级内存分析

1
2
3
4
5
6
7
8
9
10
# 1. 查看系统内存使用
free -h
cat /proc/meminfo

# 2. 查看进程内存详情
cat /proc/<pid>/status | grep -E "(VmRSS|VmSize)"
cat /proc/<pid>/smaps | grep -E "(Size|Rss)" | awk '{sum+=$2} END {print sum " KB"}'

# 3. 实时监控内存变化
watch -n 1 'ps aux --sort=-%mem | head -10'

Valgrind 检测 C/C++内存泄漏

1
2
3
4
5
6
7
# 编译时添加调试信息
gcc -g -o myapp myapp.c

# 使用valgrind检测
valgrind --tool=memcheck --leak-check=full ./myapp

# 关注输出中的 "definitely lost" 和 "possibly lost"

预防措施

代码审查要点

  1. 资源管理:确保每个 new/malloc 都有对应的 delete/free
  2. 智能指针:C++优先使用 shared_ptr/unique_ptr
  3. defer 语句:Go 中及时释放资源
  4. try-with-resources:Java 中自动管理资源

监控告警

1
2
3
4
5
6
7
8
9
10
11
12
# Prometheus告警规则
- alert: HighMemoryUsage
expr: (process_resident_memory_bytes / 1024 / 1024) > 2000
for: 5m
annotations:
summary: "Process memory usage > 2GB"

- alert: MemoryGrowthRate
expr: increase(process_resident_memory_bytes[1h]) / 1024 / 1024 > 500
for: 10m
annotations:
summary: "Memory growth rate > 500MB/hour"

内存泄漏问题往往隐蔽性强,影响面广。建立完善的监控和快速定位能力,是保障服务稳定性的关键。