快速定位Java应用卡顿的原因
背景
同事的环境说出现了一周的卡顿现象.
元旦加班期间告诉我时已经是2024.1.1下午五点了.
当时没有来得及去查看.
上班之后发现问题很简单. 不过为了能够指导一下后续的工作.还是在这里总结一下操作过程.
判断问题的整体思路
0. 同事告知出现卡顿.
询问卡顿的现象: 程序启动后, 运行一段时间后就卡顿. 无法缓解.
1. 查看宿主机以及虚拟机的情况:
判断是否是宿主机性能导致问题. 发现宿主机的CPU较高, 但是大部分CPU在这一台机器上面.
2. 进入Linux系统. top -Hp 进行观察
发现java进程占用CPU忽高忽低, 基本确认是在fullGC. 怀疑产品有内存泄露.
3. jstat -gcutil $pid 1000 1000
查看GC次数, 发现基本上10秒左右一次FullGC.基本确认存在问题.
4. jcmd $pid GC.heap_dump /root/20240102.dump
转储dump文件, 并且使用mat进行分析
5. 查看leak suspect 以及进行查看堆栈信息. 按照使用的堆区大小进行排序
定位到具体的内存占用较高的点. 发现是发送消息时因为获取了所有的消息体导致内存占用量大. 并且消息发送一分钟一次,较为频繁.
6. 反馈给业务开发, 调整消息发送时的个数限制,以及增加频率限制. 避免一次性进行所有消息的发送, 导致系统阻塞.
关于jcmd命令的使用
jcmd 从jdk7 开始就是java自带的应用了
其实是java应用里面进行定位问题的最佳工具之一.
需要建议, 如果程序使用哪个版本的java, 必须使用相同版本的 jcmd 等工具进行分析
不然那会出现加载失败等的问题.
jcmd 的命令介绍
jcmd -l
与jps 一样 展示所有的 正在运行的java 进程.
jcmd $pid help
查看jcmd的帮助列表, 需要说明. 不同版本的jcmd包含的命令不太一样
可以直接使用jcmd 0 help 进行查看.
[root@CentOS8 ~]# jcmd 0 help
2096872:
The following commands are available:
VM.native_memory
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
VM.classloader_stats
GC.rotate_log
Thread.print
GC.class_stats
GC.class_histogram
GC.heap_dump
GC.finalizer_info
GC.heap_info
GC.run_finalization
GC.run
VM.uptime
VM.dynlibs
VM.flags
VM.system_properties
VM.command_line
VM.version
help
比较常用的其实有
jcmd 0 VM.flags
jcmd 0 VM.system_properties
jcmd 0 VM.command_line
jcmd 0 GC.heap_info
jcmd 0 GC.class_histogram
jcmd 0 Thread.print
jcmd 0 GC.heap_dump /path/to/gcfile
除此之外 还有
jstat -gcutil pid 1000 1000 每秒钟展示一次gc信息.