网站首页 > java教程 正文
背景故事
某次系统更新后,服务器频繁出现「服务下线-上线」的报警通知,就像家里的灯泡忽明忽暗,说明系统可能存在严重问题。
第一步:用「诊断器」Arthas 做初步诊断
1. 安装 Arthas
Arthas 是 Java 应用的「诊断器」,下载后直接运行即可(官方文档[1])。
2. 查看系统仪表盘
输入 dashboard 命令,就像打开汽车的仪表盘,能看到 CPU、内存等关键指标:
dashboard
dashboard 指令的输出结果
发现异常:内存使用量接近上限(好比油箱快见底了),但 CPU 正常。
3. 重点监测内存变化
输入 memory 命令,持续观察内存变化:
memory
memory 指令的输出结果
关键线索:heap(堆内存)和 eden space(新对象存放区)持续增长,像水池水位不断上涨,说明可能有内存泄漏(水桶漏水了)。
4. 给内存拍个快照
用 heapdump 命令生成内存快照(类似给漏水的水桶拍照):
heapdump arthas-output/dump.hprof
小贴士:可多次拍照,方便对比不同时间点的内存状态。
第二步:用「X光机」MAT 分析内存快照
1. 下载并打开 MAT 工具
Eclipse Memory Analyzer(MAT) 是一个快速且功能丰富的 Java 堆分析器,可帮助您查找内存泄漏并减少内存消耗。
MAT 是分析内存的「X光机」,官网下载[2]后打开快照文件 dump.hprof。
2. 查找「大块头」对象
点击 Dominator Tree(支配树),像查账一样找出占用内存最多的对象:
Dominator Tree 显示的异常点
发现疑点:一个超长的 SQL 查询字符串(占用 2.53 MB),内容如下:
SELECT COUNT(*) FROM imes_schedule_batch_progress WHERE is_delete=0 AND batch_no IN ('12116209-A1','12116209-H1-A1'...)--包含10万个参数!
3. 风险分析
- o 问题 1:频繁生成这种「巨型 SQL」会拖慢垃圾回收(就像频繁倒垃圾)。
- o 问题 2:如果 SQL 被缓存长期持有,会导致内存泄漏(垃圾一直不清理)。
第三步:结合日志定位代码问题
1. 查看日志中的请求参数
在日志中发现异常请求:
{"batchNoList": []} -- 参数为空却查询了全部数据!
异常日志内容
真相大白:
某个接口(/batch/getSimpleBatchInfo)未校验参数,当传入空列表时,错误地查询了全量数据(10 万个批次号),拼接成超长 SQL。
第四步:修复优化
1. 代码修复
- o 修复逻辑:增加参数校验,禁止空列表查询。
- o 优化 SQL:改用参数化查询(类似「打包传送」数据,避免拼接字符串)。
2. 验证效果
重启服务后持续监控,内存使用量稳定,像修复了漏水的水管:
重启服务后,内存变化情况
总结:OOM 排查四步法
- 1. 仪表盘观察(dashboard) → 看整体健康状态
- 2. 内存监测(memory) → 找水位上涨趋势
- 3. 内存快照分析(heapdump + MAT) → 定位「大块头」对象
- 4. 日志溯源 → 结合代码修复问题
避坑指南:
- o 避免拼接超长 SQL,改用参数化查询
- o 重要接口必须校验参数合法性
猜你喜欢
- 2025-04-07 Java内存泄漏的原因(java内存泄露的原因)
- 2025-04-07 探秘Java程序的“内存大爆炸”:JVM内存溢出问题排查
- 2025-04-07 什么是内存泄漏,常见引起引起内存泄漏的原因,及解决办法
- 2025-04-07 面试官:Java 内存泄漏了,怎么排查?
- 2025-04-07 Java内存泄漏排查实战:从MAT到Arthas,手把手教你揪出元凶!
- 2025-04-07 实战一次完整的JVM堆外内存泄漏故障排查记录
- 2025-04-07 面试官:ThreadLocal为什么会发生内存泄漏?
- 2025-04-07 10个java常见内存泄露场景的模拟和解决方案
- 2025-04-07 Java内存泄漏的介绍(java 内存泄露 内存溢出)
- 2025-04-07 深度剖析:如何高效排查Java程序的内存泄漏问题
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)