背景
最近发现线上的一个JAVA程序总是过段时间慢慢卡死,最后导致无法提供服务,外部请求接口超时。
经排查发现,该程序CPU及内存占用都很高,导致整个系统负载很高。
到这里,就想到了对程序内存进行分析。
排查过程
查询负载高的进程
使用top命令查询负载高的进程,获取负载高的进程id
由此,可见,该进程id为4140。
查看该进程负载最高的线程
使用 top -H -p 进程id ,命令查看某个进程进程负载最高的进程,并获取该进程id, 这里的进程id为4140.
由此可以看出,消耗资源的线程id为4152.
转换线程id为16进制
用 printf "%x\n" 4152 ,命令转换结果为1038
查询繁忙线程的线程信息
用 jstack 4140 | grep “1038” -A 100,结果如下:
“VM Thread” os_prio=0 tid=0x00007f179813e800 nid=0x1038 = runnable
“Gang worker#0 (Parallel GC Threads)” os_prio=0 tid=0x00007f1798021000 nid=0x1a03a runnable
“Gang worker#1 (Parallel GC Threads)” os_prio=0 tid=0x00007f1798023000 nid=0x1a03b runnable
“Gang worker#2 (Parallel GC Threads)” os_prio=0 tid=0x00007f1798025000 nid=0x1a03c runnable
“Gang worker#3 (Parallel GC Threads)” os_prio=0 tid=0x00007f1798026800 nid=0x1a03d runnable
“Concurrent Mark-Sweep GC Thread” os_prio=0 tid=0x00007f1798069800 nid=0x1a03e runnable
“VM Periodic Task Thread” os_prio=0 tid=0x00007f17981b6800 nid=0x1a048 waiting on condition
JNI global references: 2651
通过以上信息,我们可以看到VM Thread字样,可以判断为虚拟机线程频繁GC导致问题发生。如果没有这个字样就是程序线程消耗资源过高导致错误问题,处理方法就要另外处理了。
导出进程堆内存并定位代码
使用jmap -dump:format=b,file=heap.hprof 4140 导出进程堆内存。
用jvisualvm命令可以查看并分析堆信息。
经过分析发现堆内存中有个AES加密使用的类的对象引用过多,占了1.9G内存,因此,AES加密代码存在问题,最终解决问题。