JMeter 长时间压测出现 OOM,你会用哪些工具定位并解决
解读
面试官想验证三件事:
- 你是否真的在生产级压测里遇过“跑一夜就挂”的 OOM,而不是只跑过 5 分钟 demo;
- 能否用国内开发/运维环境最常见的命令行+开源工具快速拿到“内存是谁吃了”的直接证据;
- 能否把“定位”和“解决”串成闭环:既让当晚的压测先跑完,又能让开发第二天把根因改掉。
回答时切忌只背“加 -Xmx”或“换 GUI 到非 GUI”,必须体现“采样→分析→调优→回归”四步,并给出可落地的数字指标(如 Old 区 92%、FGC 每 3 min 一次、线程数 5 k 等)。
知识点
- JMeter 内存模型:
– 每个并发线程(Thread Group)= 一个 Java Thread + 一套 SampleResult 列表;
– 监听器(View Results Tree、Aggregate Report、BackendListener)在内存中累加数据;
– 长链路断言、大响应体(>2 MB JSON)未关闭,会导致 char[]/byte[] 在 Eden 区无法及时释放。 - 国内可落地的采样三件套:
– jstat -gc -t -h5 pid 1s >> gc.log(无侵入,秒级);
– jmap -histo:live pid | head -n 30(直看 Top 对象);
– arthas heapdump --live /tmp/jmeter.hprof(阿里开源,生产可动态 dump,无需重启)。 - 解决套路:
– 治标:非 GUI 模式 + 关闭所有累加监听器 + 打开 -XX:+UseG1GC -Xms4g -Xmx4g -XX:MaxGCPauseMillis=200;
– 治本:把“写文件”监听器换成 InfluxDBBackendListener + Grafana,压测机只负责发压力,数据走网络;
– 补充:若断言需解析大 JSON,改用 JSR223 + Gson 流式解析 + 手动 clear。
答案
我上周刚帮支付团队定位一个 12 小时 OOM 问题,思路如下:
- 现场止血
先用ps -ef | grep ApacheJMeter拿到 pid,发现 Old 区 98%,FGC 每 150 s 一次。
立刻用arthas dashboard确认线程数 4 800,正常应该 2 000,怀疑监听器堆积。 - 采样定位
a)jstat -gc -t pid 1s持续 2 min,发现 Old 区上涨斜率 4.2 MB/s,与并发数成正比;
b)jmap -histo:live | head显示org.apache.jmeter.samplers.SampleResult占 1.7 GB,排第一;
c) 为防二次 OOM,用arthas heapdump --live生成 3.9 GB hprof,拉到本地 MAT,直方图显示char[]1.2 GB,GC Root 是ResultCollector#sampleStore。 - 根因确认
脚本里开了“View Results in Table”+“Save Responses to a file”两项,且未勾选“仅保存错误”。12 小时 * 1 200 TPS * 2 KB 响应体 ≈ 100 GB 内存引用,Old 区放不下。 - 解决措施
– 当晚:把 JMeter 切到非 GUI,删除所有可视化监听器,加-Xms4g -Xmx4g -XX:+UseG1GC -XX:+ExitOnOutOfMemoryError,重启压测,Old 区稳定在 1.2 GB,FGC 降到 1 次/小时;
– 次日:把 BackendListener 指向内部 InfluxDB,Grafana 模板 ID 1152,压测机内存降到 1.5 GB;
– 长效:把大响应体断言改成 JSR223 + Jackson Streaming API,并在 tearDown 线程组里手动sampler.getResponseData().length=0,SampleResult 不再持引用。
回归验证:同样 12 小时 1 200 TPS 场景,Old 区峰值 1.4 GB,无 FGC,满足 SLA。
拓展思考
- 如果压测机是容器(公司 K8s 压测池),记得把
-XX:MaxRAMPercentage=75.0写进 Dockerfile,防止 cgroup 限制下 JVM 仍按宿主机内存算默认堆; - 对 10 k+ 超高并发,可考虑 JMeter 5.5 的“RedisBackendListenerClient”,把 SampleResult 直接序列化到 Redis Stream,压测机完全无状态;
- 若 MAT 发现内存泄漏在第三方插件(如 MQTT、DubboSampler),可临时用
arthas redefine热替换 class,先让当晚任务跑完,第二天再提 PR 给社区。