天天看点

JVM问题排查步骤 

1、执行jps命令查看服务进程是否还存在:jps -lv

2、执行top命令查看CPU和内存使用率。若发现有一或多个CPU或内存的使用率居高不下(例如80%~100%),且是Java相关进程引起的,若不是则排查其他问题,如系统问题。用docker运行top命令报错“TERM environment variable not set.”,解决办法是:在运行top时加上 -b参数。top -bc | top -b [pid]。

3、执行top (-b) -Hp ${pid}  (d命令指定每两次屏幕信息刷新之间的时间间隔。步骤2中cpu或内存使用率过高的Java进程号)。若是接口反应慢问题,则可在此时请求接口,观察得到持续占用CPU或内存使用率过高的线程号(用于后续步骤5)。    

    3.1、若cpu使用率过高,执行jstack ${pid} > jstack.log   (步骤2中pid进程号)。得到该Java进程的线程快照jstack.log。

         3.1.1、执行less jstack.log ,将之前有问题的(步骤3中)线程号转换为16进制,在线程快照中查找到该线程,输入: /16进制线程号(printf "%x\n"  可以得到16进制数)  enter  ,查看其线程相关信息,

                    查找与本服务密切相关的信息(如自定义类),确定问题所在行,解决问题,重试。

                    若发现是JVM的垃圾回收线程。再搜索整个文件,没有被死锁的线程。于是怀疑内存没有正确释放,JAVA进程已使用的内存,已经达到了分配给JVM的最大内存。导致垃圾回收频繁执行FullGC,占用了CPU。

                    执行jstat -gccasue ${pid} ${refresh time} 【jstat -gccause 1 1000】若发现年轻代,老年代内存使用率太高。进一步证实之前的怀疑。jstat使用详解 

     3.2、若内存使用率过高,执行jmap -histo:live ${pid}  | head -10 ,若还不能确定造成内存泄漏的类, 则执行jmap -dump:format=b,file=${dumpFileName} ${pid} 得到当前内存快照。

4. 使用eclipse的memory analyzer导入内存快照,进行分析。找出内存异常的对象。

5. 修改程序的BUG。

6. BUG修复以后,继续定时获取内存快照,持续观察。直到彻底解决问题。

若是自己熟悉的代码,通过业务日志与直觉往往也能比较快的定位到问题,很多次都是相信直觉,对于心中对代码有比较熟悉的基础上。

具体测试例子:subao-product  内存(MB):700~700 ,启动命令:java -jar -Xms350m -Xmx350m -XX:-UseAdaptiveSizePolicy -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/alidata1/admin/subao-product/heapdump.hprof subao-product.jar