定位Java程序内存使用过高或者内存泄漏的问题跟CPU也类似,一般可以分为以下3个步骤:
通过 top -c
(然后按 Shift+M
按内存排序),或者 htop
等工具定位到具体的高内存进程。假设定位到的进程ID为14279。
top -H -p 14279
(然后按 Shift+M
按内存排序)定位占内存的线程:
%Cpu(s): 0.5 us, 0.7 sy, 0.0 ni, 98.8 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st KiB Mem : 8168236 total, 231696 free, 3660496 used, 4276044 buff/cache KiB Swap: 969964 total, 969964 free, 0 used. 4197860 avail Mem PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 14293 weiping 20 0 4508772 97036 18112 S 10 12 152:35.42 java 14279 weiping 20 0 4508772 97036 18112 S 5.0 1.2 0:00.00 java 14282 weiping 20 0 4508772 97036 18112 S 0.0 1.2 0:00.37 java
ps p 14279 -L -o pcpu,pmem,pid,tid,time,tname,cmd |wc -l
通过以上二步确认是否线程开多了,还是单个线程内存占用过多导致。
通过 thread tid
直接查看指定线程的堆栈信息:
[arthas@42436]$ thread 91 "MQ-AsyncTraceDispatcher-Thread-ce0ebd2a-5807-4053-ae3c-7472fe4b5aef" Id=91 TIMED_WAITING on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@774405a1 at sun.misc.Unsafe.park(Native Method) -- waiting on java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject@774405a1 at java.util.concurrent.locks.LockSupport.parkNanos(LockSupport.java:215) at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(AbstractQueuedSynchronizer.java:2078) at java.util.concurrent.ArrayBlockingQueue.poll(ArrayBlockingQueue.java:418) at org.apache.rocketmq.client.trace.AsyncTraceDispatcher$AsyncRunnable.run(AsyncTraceDispatcher.java:238) at java.lang.Thread.run(Thread.java:748) Affect(row-cnt:0) cost in 2 ms.
更多官方详细文档: Arthas命令文档——thread
如果是线上环境,注意dump之前必须先将流量切走,否则大内存dump是直接卡死服务。 ``` # dump当前快照 jmap -dump:live,format=b,file=dump.hprof <pid> # 触发full gc,然后再dump一次 jmap -dump:live,format=b,file=dump_gc.hprof <pid> ``` dump:live的作用是会触发Full GC,然后再dump数据,用作gc前后的数据做对比。
如果快照文件不大,可以下载到本地,然后通过 MAT 分析。
如果快照文件不大,也可以上传到 https://fastthread.io/ 分析。
如果快照文件很大,可以在服务器上直接分析:
faceless@ttg12:~/tmp$ jhat dump.hprof Reading from dump.hprof... Dump file created Mon Jun 22 14:33:00 CST 2020 Snapshot read, resolving... Resolving 36246 objects... Chasing references, expect 7 dots....... Eliminating duplicate references....... Snapshot resolved. Started HTTP server on port 7000 Server is ready.
分析完成后,访问 http://ttg12 :7000,如下图:
点进入看实例数(图来自网络,这里只是示意):
找到数量大的业务类,比如上图中是 Packet
。然后一路点进去,跟踪引用路径,看到底是哪个类引用的。
TO BE FINISHED——也可以通过服务器上的Arthas分析。