Java虚拟机问题排查
Java虚拟机问题排查
CPU 飚高
思路
首先找到 CPU 飚高的那个 Java 进程,因为你的服务器会有多个 JVM 进程,然后找到那个进程中的 “问题线程”,最后根据线程堆栈信息找到问题代码,最后对代码进行排查。
步骤
- 通过 top 命令找到 CPU 消耗最高的进程,并记住进程 ID
- 再次通过 top -Hp [进程 ID] 找到 CPU 消耗最高的线程 ID,并记住线程 ID.
- 通过 JDK 提供的 jstack 工具 dump 线程堆栈信息到指定文件中。具体命令:jstack -l [进程 ID] >jstack.log
由于刚刚的线程 ID 是十进制的,而堆栈信息中的线程 ID 是16进制的,因此我们需要将10进制的转换成16进制的,并用这个线程 ID 在堆栈中查找。使用 printf “%x\n” [十进制数字] ,可以将10进制转换成16进制
- 通过刚刚转换的16进制数字从堆栈信息里找到对应的线程堆栈,就可以从该堆栈中看出端倪
可能的情况
- 某个业务死循环没有出口
- C2 编译器执行编译时抢占 CPU
当 Java 某一段代码执行次数超过10000次(默认)后,就会将该段代码从解释执行改为编译执行,也就是编译成机器码以提高速度。而这个 C2编译器就是做这个的。如何解决呢?项目上线后,可以先通过压测工具进行预热,这样,等用户真正访问的时候,C2编译器就不会干扰应用程序了。
- GC 线程导致,那么极有可能是 Full GC ,那么就要进行 GC 的优化。
内存问题排查
思路
通常,内存的问题就是 GC 的问题,因为 Java 的内存由 GC 管理。有2种情况,一种是内存溢出了,一种是内存没有溢出,但 GC 不健康。
步骤
- 内存溢出的情况可以通过加上 -XX:+HeapDumpOnOutOfMemoryError 参数,该参数作用是:在程序内存溢出时输出 dump 文件。
- dump文件被常用的MAT,Jprofile,jvisualvm 等工具都可以分析,这些工具都能够看出到底是哪里溢出,哪里创建了大量的对象等等信息。
什么是健康的GC
一般来说,YGC 5秒一次左右,每次不超过50毫秒,FGC 最好没有,CMS GC 一天一次左右。
而 GC 的优化有2个维度,一是频率,二是时长。
YGC
YGC频率过低
如果 YGC 超过5秒一次,甚至更长,说明系统内存过大,应该缩小容量,
YGC频率过高
说明 Eden 区过小,可以将 Eden 区增大,但整个新生代的容量应该在堆的 30% - 40%之间,eden,from 和 to 的比例应该在 8:1:1左右,这个比例可根据对象晋升的大小进行调整。
YGC时间过长
YGC 有2个过程,一个是扫描,一个是复制,通常扫描速度很快,复制速度相比而言要慢一些
- 如果每次都有大量对象要复制,就会将 STW 时间延长,
- StringTable ,这个数据结构中存储着 String.intern 方法返回的常连池的引用,YGC 每次都会扫描这个数据结构(HashTable),如果这个数据结构很大,且没有经过 FGC,那么也会拉长 STW 时长
- 操作系统的虚拟内存,当 GC 时正巧操作系统正在交换内存,也会拉长 STW 时长。
FGC
FGC 我们只能优化频率,无法优化时长,因为这个时长无法控制。
影响FGC频率的因素
- Old 区内存不够
- 元数据区内存不够
- System.gc()
- jmap 或者 jcmd工具导致
- CMS Promotion failed 或者 concurrent mode failure
- JVM 基于悲观策略认为这次 YGC 后 Old 区无法容纳晋升的对象,因此取消 YGC,提前 FGC
可能的情况
- Old 区内存不够导致 FGC
- FGC之后还有大量对象,说明 Old 区过小,应该扩大 Old 区
- 如果 FGC 后效果很好,说明 Old 区存在了大量短命的对象,优化的点应该是让这些对象在新生代就被 YGC 掉,通常的做法是增大新生代;如果有大而短命的对象,通过参数设置对象的大小,不要让这些对象进入 Old 区,还需要检查晋升年龄是否过小
- 如果 YGC 后,有大量对象因为无法进入 Survivor 区从而提前晋升,这时应该增大 Survivor 区,但不宜太大。
工具
JDK提供了很多的工具,比如 jmap ,jcmd 等,oracle 官方推荐使用 jcmd 代替 jmap
jmap 可以打印对象的分布信息,可以 dump 文件,注意,jmap 和 jcmd dump 文件的时候会触发 FGC ,使用的时候注意场景。
jinfo,该工具可以查看当前 jvm 使用了哪些参数,并且也可以在不停机的情况下修改参数。
分析 dump 文件的可视化工具,MAT,Jprofile,jvisualvm 等,这些工具可以分析 jmap dump 下来的文件,看看哪个对象使用的内存较多。
线上环境要带上 GC 日志