← 中文资源

简体中文版本

用浸泡测试检测内存泄漏

驱动数小时的重复工作负载循环,把堆内存对循环数作图,先区分泄漏与平台期再怪运行时。

阅读英文原文

目标

仪表盘里爬升的内存是有歧义的:缓存在填充、池在生长、运行时在预热。消歧的关键是横轴。把内存对完成的工作负载循环数作图并在采样间强制 GC,泄漏就无处遁形:GC 后堆仍随循环数线性上升。修复后同一张图变平,浸泡装置升级为回归门禁。

步骤要点

  1. 以固定流量循环打工作负载,每分钟采样 process_resident_memory_bytes 记入 soak.log。
  2. 把内存对循环数作图:随循环线性上升是泄漏,趋于渐近线是缓存预热。
  3. 每循环后 global.gc() 再采样,GC 后仍爬升即对象被引用持有,坐实泄漏。
  4. 稳态下隔一段循环取两份堆快照,profiler diff 点名滞留分配站点。
  5. 修复最大滞留者(无界 Map、每请求 addListener、未 clear 的 interval)后重跑浸泡验证斜率归零。

排错提示

先升后平不是泄漏,缓存、连接池、JIT 预热都会稳定下来,只有稳态后对循环数仍有斜率才是;泄漏几天才显现就缩小循环、提高速率,泄漏与操作数成正比,十倍流量把四天压缩成一小时;运行时没有快照工具就用 RSS 斜率加分配点代码审查,容器 OOM 事件做终验。

适用边界

浸泡只覆盖被测工作负载,未执行路径仍可能泄漏;RSS 含分配器开销与碎片,可能无对象泄漏也增长。

代码示例

# Sample RSS every minute while cycling the workload
for i in $(seq 1 2000); do
  curl -s -o /dev/null "http://localhost:3000/orders?page=$((i % 40))"
done &
watch -n 60 "curl -s localhost:9090/metrics | grep process_resident_memory_bytes" | tee soak.log