JVM技术专题-线上解决方案(1) GC问题分析和故障排查规划指南

前提概要

之前的JVM专题总共大致近50章节,问题介绍相关的JVM的原理分析,比较接近于理论化,并且也穿插这相关的GC问题排查和调优的技术功能实现,但是很多小伙伴都建议我多针对于实际优化角度和故障排查而言,进行相关的分析和总结,所以有了目前的【线上解决方案系列】希望大家会喜欢!

什么是GC问题

堆内内存泄漏总是和GC异常相伴。不过GC问题不只是和内存问题相关,还有可能引起CPU负载、网络问题等系列并发症,只是相对来说和内存联系紧密些,所以我们在此单独总结一下GC相关问题

使用jstat来获取当前GC分代变化信息。而更多时候,我们是通过GC日志来排查问题的,在启动参数中加上-verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+PrintGCTimeStamps来开启GC日志。

针对GC日志,我们就能大致推断出youngGC与fullGC是否过于频繁或者耗时过长,从而对症下药。我们下面将对G1垃圾收集器来做分析,这边也建议大家使用G1-XX:+UseG1GC

youngGC过频繁

youngGC频繁一般是短周期小对象较多

  • 先考虑是不是Eden区/新生代设置的太小了。

  • 看能否通过调整-Xmn、-XX:SurvivorRatio等参数设置来解决问题

如果参数正常,但是young gc频率还是太高,就需要使用JmapMAT对dump文件进行进一步排查了。

youngGC耗时过长

耗时过长问题就要看GC日志里耗时耗在哪一块了

  • 以G1日志为例,可以关注Root Scanning、Object Copy、Ref Proc等阶段

  • Ref Proc耗时长,就要注意引用相关的对象

  • Root Scanning耗时长,就要注意线程数、跨代引用

  • Object Copy则需要关注对象生存周期

而且耗时分析它需要横向比较,就是和其他项目或者正常时间段的耗时比较。比如说图中的Root Scanning和正常时间段比增长较多,那就是起的线程太多了

触发fullGC

G1中更多的还是mixedGC,但mixedGC可以和youngGC思路一样去排查。触发fullGC了一般都会有问题,G1会退化使用Serial收集器来完成垃圾的清理工作,暂停时长达到秒级别,可以说是半跪了

fullGC的原因可能包括以下这些,以及参数调整方面的一些思路:

并发阶段失败:在并发标记阶段,MixGC之前老年代就被填满了,那么这时候G1就会放弃标记周期。这种情况,可能就需要增加堆大小,或者调整并发标记线程数 -XX:ConcGCThreads

  • 晋升失败:在GC的时候没有足够的内存供存活/晋升对象使用,所以触发了FullGC

  • 这时候可以通过-XX:G1ReservePercent来增加预留内存百分比,减少-XX:InitiatingHeapOccupancyPercent来提前启动标记,-XX:ConcGCThreads来增加标记线程数也是可以的

  • 大对象分配失败:大对象找不到合适的region空间进行分配,就会进行fullGC,这种情况下可以增大内存或者增大-XX:G1HeapRegionSize

程序主动执行System.gc:不要随便写就对了 另外,我们可以在启动参数中配置-XX:HeapDumpPath=/xxx/dump.hprof来dump fullGC相关的文件,并通过jinfo来进行gc前后的dump

jinfo -flag +HeapDumpBeforeFullGC pid 
jinfo -flag +HeapDumpAfterFullGC pid

这样得到2份dump文件,对比后主要关注被gc掉的问题对象来定位问题。

你可能感兴趣的:(JVM技术专题-线上解决方案(1) GC问题分析和故障排查规划指南)