JVM线程和内存溢出问题排查思路
一、工具
Arthas:Arthas 是一款能在线查看应用 load、内存、gc、线程 等状态信息,并对业务问题进行诊断的工具,支持 JDK 6+ 和 Linux/Mac/Windows 系统。
jstack:jstack是JVM自带的Java堆栈跟踪工具,它用于打印出给定的java进程ID、core file、远程调试服务的Java堆栈信息。参考连接
jmap:jmap能够打印给定Java进程、核心文件或远程DEBUG服务器的共享对象内存映射或堆内存的详细信息。
jstat:jstat命令可以查看堆内存各部分的使用量,以及加载类的数量。
jcmd:jdk1.8开始提供了一个方便扩展的诊断命令jcmd,用来取代之前比较分散的jdk基础命令,如jps、jstack、jmap、jinfo等,并且jdk添加新的诊断功能。
二、jstack查看线程快照
用于定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等问题。
- top,查看各进程使用情况
- top -Hp pid,查看进程pid的各线程运行情况
- printf '%x\n' tid,将线程号转为16进制;其中tid为线程号
- jstack pid | grep '0x4295' -C10 --color,查看进程pid的0x4295线程快照,分析线程停顿原因和代码行。
三、jstat统计垃圾回收情况(查看gc频率)
jstat -gcutil pid
S0:幸存1区当前使用比例
S1:幸存2区当前使用比例
E:伊甸园区使用比例
O:老年代使用比例
M:元数据区使用比例
CCS:压缩使用比例
YGC:年轻代垃圾回收次数
FGC:老年代垃圾回收次数
FGCT:老年代垃圾回收消耗时间
GCT:垃圾回收消耗总时间
四、jmap查看堆内存情况、制作dump文件
jmap -heap 17038
,17038为进程号,查看进程号位17083的进程的堆内存使用情况。
jmap -dump:live,format=b,file=filename.hprof pid
,生成进程号位pid的进程的堆内存dump文件。
五、内存溢出的几个错误
outOfMemoryError 年老代内存不足。
outOfMemoryError:PermGen Space 永久代内存不足。
outOfMemoryError:GC overhead limit exceed 垃圾回收时间占用系统运行时间的98%或以上。
六、排查思路
-
通过top命令查看进程情况、找到最消耗资源的java进程,这一步在不知道哪个java程序消耗资源最大的情况执行,如果已经知道是哪个java程序,则可以直接进入第二步(这一步获得进程ID pid)
-
通过top -Hp pid,查看进程pid中最消耗资源的线程,这一步将获得线程ID tid
-
此时可以先使用jstack命令查看线程tid的运行情况
printf '%x\n' tid
这个命令将得到一个标识线程tid的十六进制值nid。jstack pid | grep nid -C10 --color
这个命令将显示线程tid(nid为十六进制表示)的线程快照,可以找到线程是否阻塞等。 -
使用jmap命令查看进程pid的堆内存使用情况
jmap -heap pid
这个命令将显示进程pid堆内存的使用情况,如果堆内存占用过高,可以使用jmap生成dump文件进行进一步分析jmap -dump:live,format=b,file=filename.hprof pid
这个命令将生成进程pid的堆内存使用情况的dump文件。除此之外也可以使用jstat命令分析垃圾回收情况,看看是否进行频繁的gc。
jstat -gcutil pid
这个命令将显示进程pid的gc频率等。 -
最后查看程序日志是否有
outOfMemoryError
、outOfMemoryError:PermGen Space
、outOfMemoryError:GC overhead limit exceed
等内存溢出相关错误,这个也可以在第一步之前查看。 -
如果确定是内存溢出问题,最好使用可视化工具分析生成的dump文件,找到内存溢出的位置。(一般在启动java程序时配置jvm保存dump文件)
注:为了出现内存溢出问题时能够排查问题,运行jar包时添加jvm配置:
java -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/data/tmp/heapdump.hprof -jar app.jar
这将保留堆内存快照,以便将来分析内存使用。
本笔记只记录每个工具可以用来查看什么信息以及什么时候可以用什么工具,并不记录上述工具的详细使用方法。