1. 启动Arthas并附加到目标JVM
# 安装Arthas(如果未安装) curl -O https://arthas.aliyun.com/arthas-boot.jar java -jar arthas-boot.jar # 选择目标Java进程的PID(输入数字) [INFO] arthas-boot version: 3.7.1 [INFO] Found existing java process, please choose one and input the serial number of the process, eg: 1. 1: 1234 org.example.Main 2: 5678 another.app.Main
2. 实时监控内存和GC状态
2.1 使用dashboard
命令
查看实时内存、GC、线程状态:
dashboard
-
观察指标:
-
heap
内存使用是否持续增长(接近max
值)。 -
GC
频率是否异常(频繁Full GC可能表明内存不足)。
-
2.2 使用jvm
命令
确认堆内存配置:
jvm
-
检查
MaxHeapSize
(即-Xmx
参数)是否合理。若配置过小,需调整JVM参数。
3. 生成Heap Dump分析
3.1 使用heapdump
命令导出堆快照
heapdump --live /tmp/heapdump.hprof
-
--live
:仅导出存活对象(减少文件大小)。 -
文件路径需有写入权限,推荐使用
/tmp
或自定义目录。
3.2 使用工具分析Heap Dump
-
将
heapdump.hprof
下载到本地,用以下工具分析:-
Eclipse MAT:查找内存泄漏(Dominator Tree、Leak Suspects)。
-
JVisualVM:直观查看大对象分布。
-
4. 在线分析内存对象
4.1 使用memory
命令查看内存占用
列出堆内存中对象实例数和内存占用:
memory
或按类名排序:
memory | grep 'java.lang.' # 过滤特定包名
4.2 使用vmtool
获取类实例详情
查看某个类的实例数量和属性:
vmtool --action getInstances --className java.util.ArrayList --express 'instances.length'
5. 检查线程和代码逻辑
5.1 使用thread
命令查看线程栈
thread -n 5 # 查看最忙的5个线程
-
检查是否有线程在大量分配对象(如循环中创建大集合)。
5.2 使用trace
或watch
跟踪方法
跟踪可能分配内存的方法:
# 监控某个方法耗时和调用栈 trace com.example.MyService processData # 查看方法参数/返回值中的大对象 watch com.example.MyService processData '{params, returnObj}' -x 3
6. 动态排查内存泄漏
6.1 使用ognl
表达式检查对象增长
多次执行以下命令,观察对象数量是否持续增长:
ognl '@java.lang.management.ManagementFactory@getMemoryMXBean().getHeapMemoryUsage().getUsed()'
6.2 使用tt
记录方法调用
记录方法调用,分析参数是否异常:
tt -t com.example.MyService addData -n 100 tt -i 1000 -w '{target,params[0]}' # 查看第1000次调用的参数
7. 确认JVM参数优化
-
如果确认是配置问题,调整JVM参数:
-Xmx4g -Xms4g -XX:+UseG1GC -XX:+HeapDumpOnOutOfMemoryError
-
-XX:+HeapDumpOnOutOfMemoryError
:OOM时自动生成堆快照。
常见原因总结
-
内存泄漏:对象因代码逻辑(如静态集合、未关闭资源)无法回收。
-
配置不足:
-Xmx
设置过小,无法承载业务负载。 -
大对象分配:一次性加载超大文件或缓存。
-
GC效率低:老年代碎片化或GC算法不匹配。
通过以上步骤,可以快速定位是配置问题、代码缺陷还是资源管理不当导致的OOM。