JVM的GC日志详解分析及配置(一)

JVM GC日志参数

案例:
2021-03-25T13:00:41.631+0800: 4.013: [GC (Allocation Failure) [PSYoungGen: 419840K->20541K(472064K)] 419840K->20573K(996352K), 0.0118345 secs] [Times: user=0.00 sys=0.00, real=0.01 secs]

详细内容如下:

  • 2021-03-25T13:00:41.631+0800:GC发生的时间点。
  • 4.013:系统运行多久之后发生的GC,单位秒,这里就是系统运行 4.013 秒后发生了一次GC。
  • GC (Allocation Failure):说明了触发GC的原因,这里是指对象分配失败导致的GC。
  • PSYoungGen:指触发的是年轻代的垃圾回收,使用的是 Parallel Scavenge 垃圾回收器。
  • 419840K->20541K:对年轻代执行了一次GC,GC之前年轻代使用了 419840K,GC之后有 20541K 的对象活下来了。
  • (472064K):年轻代可用空间是 472064K,即 461 M,为什么是461M呢?因为新生代大小为 512M,Eden 区占 409.6M,两块 Survivor 区各占 51.2M,所以年轻代的可用空间为 Eden+1个Survivor的大小,即460.8M,约为461M。
  • 419840K->20573K:GC前整个堆内存使用了 419840K,GC之后堆内存使用了 20573K。
  • (996352K):整个堆的大小是 996352K,即 973M,其实就是年轻代的 461M + 老年代的 512 M
  • 0.0118345 secs:本次GC耗费的时间
  • Times: user=0.00 sys=0.00, real=0.01 secs:本次GC耗费的时间
Heap
 PSYoungGen      total 472064K, used 406352K [0x00000000e0000000, 0x0000000100000000, 0x0000000100000000)
  eden space 419840K, 93% used [0x00000000e0000000,0x00000000f7f00528,0x00000000f9a00000)
  from space 52224K, 27% used [0x00000000f9a00000,0x00000000fa7d3d70,0x00000000fcd00000)
  to   space 52224K, 0% used [0x00000000fcd00000,0x00000000fcd00000,0x0000000100000000)
 ParOldGen       total 524288K, used 189923K [0x00000000c0000000, 0x00000000e0000000, 0x00000000e0000000)
  object space 524288K, 36% used [0x00000000c0000000,0x00000000cb978d08,0x00000000e0000000)
 Metaspace       used 111852K, capacity 117676K, committed 117888K, reserved 1153024K
  class space    used 13876K, capacity 14914K, committed 14976K, reserved 1048576K

详细内容如下:

  • PSYoungGen total 472064K, used 406352K:指 Parallel Scavenge 回收器负责的年轻代总共有 472064K(461M)内存,目前使用了 406352K (396.8M)。
  • eden space 419840K, 93% used:Eden 区的空间为 419840K(410M),已经使用了 93%。
  • from space 52224K, 27% used:From Survivor 区的空间为 52224K(51M),已经使用了 27%。
  • to space 52224K, 0% used:To Survivor 区的空间为 52224K(51M),使用了 0%,就是完全空闲的。
  • ParOldGen total 524288K, used 189923K:指 Parallel Old 回收器负责的老年代总共有 524288K(512M),目前使用了 189923K(185.4M)。
  • object space 524288K, 36% used:老年代空间总大小 524288K(512M),使用了 36%。
  • Metaspace & class space:Metaspace 元数据空间和Class空间,总容量、使用的内存等。
    JVM的GC日志详解分析及配置(一)_第1张图片
-XX:+PrintGC(简单模式)
12.097: [GC (Allocation Failure)  419840K->18067K(996352K), 0.0197196 secs]
30.677: [Full GC 243120K->241951K(629760K), 1.5589690 secs]

这个参数只是开启了简单的日志模式,为每一次新生代(Young Generation)的GC和每一次的Full GC 打印一行信息,

首先是GC类型(GC或者Full GC)然后是括号里是GC原因(Allocation Failure:分配对象空间不足导致新生代GC),然后是GC之前和GC之后已使用的堆空间,括号里是当前的堆容量,最后是本次GC的耗时时间(以秒计)。

第一行的意思就是新生代GC已使用的堆空间从419840K减少到18067K,当前的堆容量996352K,GC持续时间是0.0197196秒。

简单模式的GC日志格式是与GC算法无关的,日志没有提供太多的信息,也无法从日志里判定GC是否将一些对象从Young Generation移到了Old Generation。所以详细模式GC更有用些。

-XX:PrintGCDetails(详细模式)

使用这个命令,就是开启了详细的GC日志模式。在这种模式下,日志格式和所使用的GC算法有关,

6.609: [GC (Allocation Failure) [PSYoungGen: 419840K->17473K(472064K)] 419840K->17561K(996352K), 0.0175394 secs] [Times: user=0.13 sys=0.00, real=0.02 secs] 
12.399: [GC (Allocation Failure) [PSYoungGen: 437313K->32044K(472064K)] 437401K->32156K(996352K), 0.0302068 secs] [Times: user=0.11 sys=0.00, real=0.03 secs] 
[Full GC
    [PSYoungGen: 10752K->9707K(142848K)]
    [ParOldGen: 232384K->232244K(485888K)] 243136K->241951K(628736K)
    [PSPermGen: 3162K->3161K(21504K)], 1.5265450 secs
]

可以很容易发现,这是一次在Young Generation中的GC,它将新生代已使用的堆空间从419840K减少到17473K,新生代可用空间为472064K,GC前整个堆使用了419840K,GC后整个堆使用了17561K,整个堆的大小是996352K(新生代+老年代),耗时0.0175394秒,所使用的垃圾回收器是PS(Parallel Scavenge)。

Times包含了GC所使用的CPU时间信息(user+sys=0.13s时间之和),分别为操作系统的用户空间和系统空间所使用的时间,还有GC运行的真实时间(real=0.02 secs,0.02是近似值),如果CPU时间(0.13s)明显多于真实(real=0.02)时间,我们可以得出的结论:GC使用了多线程运行,这样的话CPU时间就是所有GC线程所花费的CPU时间的总和。

Full GC类似。Full GC也可以通过显示的请求而触发,可以是通过应用程序,或者是一个外部的JVM接口,这样触发的GC可以很容易在日志里分辨出来,因为输出的日志是以“Full GC(System)”开头的,而不是“Full GC”。

对于Serial垃圾收集器,详细的GC日志和Throughput垃圾收集器是非常相似的。唯一的区别是不同的generation日志可能使用了不同的GC算法(例如:old generation的日志可能以Tenured开头,而不是ParOldGen)。使用垃圾收集器作为一行日志的开头可以方便我们从日志就判断出JVM的GC设置。

对于CMS垃圾收集器,young generation的详细日志也和Throughput垃圾收集器非常相似,但是old generation的日志却不是这样。对于CMS垃圾收集器,在old generation中的GC是在不同的时间片内与应用程序同时运行的。GC日志自然也和Full GC的日志不同。而且在不同时间片的日志夹杂着在此期间young generation的GC日志。但是了解了上面介绍的GC日志的基本元素,也不难理解在不同时间片内的日志。只是在解释GC运行时间时要特别注意,由于大多数时间片内的GC都是和应用程序同时运行的,所以和那种独占式的GC相比,GC的持续时间更长一些并不说明一定有问题。

正如我们在第7节中所了解的,即使CMS垃圾收集器没有完成一个CMS周期,Full GC也可能会发生。如果发生了GC,在日志中会包含触发Full GC的原因,例如众所周知的”concurrent mode failure“(并发回收失败)。

-XX:+PrintGCTimeStamps和-XX:+PrintGCDateStamps

使用-XX:PrintGCTimeStamps可以将实际和日期也加在GC日志中,表示JVM启动至今的时间戳会被添加到每一行中。

6.195: [GC (Allocation Failure) [PSYoungGen: 419840K->17894K(472064K)] 419840K->17982K(996352K), 0.0213569 secs] [Times: user=0.00 sys=0.03, real=0.02 secs] 

如果指定了-XX:PrintGCDateStamps,每一行就添加上了绝对的日期和时间。

2021-03-31T13:58:47.268+0800: 6.963: [GC (Allocation Failure) [PSYoungGen: 419840K->16662K(472064K)] 419840K->16750K(996352K), 0.0325293 secs] [Times: user=0.08 sys=0.02, real=0.03 secs] 

如果需要也可以同时使用两个参数。推荐同时使用这两个参数,因为这样在关联不同来源的GC日志时很有帮助。

-Xloggc

缺省的GC日志输出到终端,-Xloggc:./gc.log指定输出到指定的文件,需要注意这个参数隐式的设置了参数-XX:+PrintGC和-XX:+PrintGCTimeStamps,但为了防止在新版本的JVM中有任何变化,建议显示的设置这些参数。

可管理的JVM参数,一个常常被讨论的问题就是生产环境中的GC日志是否应该开启,因为它所产生的开销通常都非常有限,因此我建议需要开启,但并不一定在启动JVM时就必须指定GC日志参数。

HotSpot JVM有一类特别的参数叫做可管理的参数,对于这些参数,可以在运行时修改它们的值,我们这里所讨论的所有参数以及以“PrintGC”开头的参数都是可管理的参数。这样在任何时候我们都可以开启或关闭GC日志,比如我们可以使用JDK自带的jinfo工具来设置这些参数,或者通过JMX客户端调用HotSpotDiagnostic MXBean的setVMOption方法来设置这些参数。例如:对PrintGC设置,参数1:PrintGC,参数2:true。打印日志即可设置成功。

-XX:+PrintGCApplicationConcurrentTime
2021-03-31T15:14:11.961+0800: 6.454: Application time: 0.1916132 seconds
2021-03-31T15:14:11.961+0800: 6.454: [GC (Allocation Failure) [PSYoungGen: 419840K->16530K(472064K)] 419840K->16618K(996352K), 0.0182229 secs] [Times: user=0.13 sys=0.00, real=0.02 secs] 

打印每次垃圾回收前,程序未中断的执行时间。

-XX:+PrintGCApplicationStoppedTime
2021-03-31T15:17:27.106+0800: 0.408: Application time: 0.0001266 seconds
2021-03-31T15:17:27.106+0800: 0.408: Total time for which application threads were stopped: 0.0000742 seconds, Stopping threads took: 0.0000398 seconds

打印垃圾回收期间程序暂停的时间,可以与上面的混合使用

-XX:PrintHeapAtGC

打印GC前后的详细堆栈信息

{Heap before GC invocations=1 (full 0):
 PSYoungGen      total 472064K, used 419840K [0x00000000e0000000, 0x0000000100000000, 0x0000000100000000)
  eden space 419840K, 100% used [0x00000000e0000000,0x00000000f9a00000,0x00000000f9a00000)
  from space 52224K, 0% used [0x00000000fcd00000,0x00000000fcd00000,0x0000000100000000)
  to   space 52224K, 0% used [0x00000000f9a00000,0x00000000f9a00000,0x00000000fcd00000)
 ParOldGen       total 524288K, used 0K [0x00000000c0000000, 0x00000000e0000000, 0x00000000e0000000)
  object space 524288K, 0% used [0x00000000c0000000,0x00000000c0000000,0x00000000e0000000)
 Metaspace       used 20878K, capacity 21480K, committed 21632K, reserved 1069056K
  class space    used 2766K, capacity 2937K, committed 2944K, reserved 1048576K
2021-03-31T15:23:07.849+0800: 8.961: [GC (Allocation Failure) [PSYoungGen: 419840K->14996K(472064K)] 419840K->15084K(996352K), 0.0182397 secs] [Times: user=0.00 sys=0.01, real=0.02 secs] 
Heap after GC invocations=1 (full 0):
 PSYoungGen      total 472064K, used 14996K [0x00000000e0000000, 0x0000000100000000, 0x0000000100000000)
  eden space 419840K, 0% used [0x00000000e0000000,0x00000000e0000000,0x00000000f9a00000)
  from space 52224K, 28% used [0x00000000f9a00000,0x00000000fa8a5260,0x00000000fcd00000)
  to   space 52224K, 0% used [0x00000000fcd00000,0x00000000fcd00000,0x0000000100000000)
 ParOldGen       total 524288K, used 88K [0x00000000c0000000, 0x00000000e0000000, 0x00000000e0000000)
  object space 524288K, 0% used [0x00000000c0000000,0x00000000c0016010,0x00000000e0000000)
 Metaspace       used 20878K, capacity 21480K, committed 21632K, reserved 1069056K
  class space    used 2766K, capacity 2937K, committed 2944K, reserved 1048576K
}
-XX:+PrintFlagsFinal

可以在启动参数中添加 -XX:+PrintFlagsFinal 参数,将会打印系统的所有参数,就可以看到自己配置的参数或系统的默认参数了,这个参数配置暂时用不到,只有在检查系统配置的时候才会使用,也可以通过JMX或者jdk自带的java Visual查看配置参数。这个是在系统启动参数里显示:

    uintx MaxMetaspaceExpansion                     = 5451776                             {product}
    uintx MaxMetaspaceFreeRatio                     = 70                                  {product}
    uintx MaxMetaspaceSize                         := 134217728                           {product}
    uintx MaxNewSize                               := 536870912                           {product}
     intx MaxNodeLimit                              = 75000                               {C2 product}
 uint64_t MaxRAM                                    = 0                                   {pd product}
    uintx MaxRAMFraction                            = 4                                   {product}
   double MaxRAMPercentage                          = 25.000000                           {product}
     intx MaxRecursiveInlineLevel                   = 1                                   {product}
    uintx MaxTenuringThreshold                      = 15                                  {product}
     intx MaxTrivialSize                            = 6                                   {product}
     intx MaxVectorSize                             = 32                                  {C2 product}
    uintx MetaspaceSize                            := 134217728                           {pd product}

总结(GC日志打印参数配置):

打印GC日志参数配置:

方式一:

只打印详细GC日志并输出到指定文件

-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-Xloggc:./gc.log

结果:

2021-03-31T15:31:05.603+0800: 6.487: [GC (Allocation Failure) [PSYoungGen: 419840K->16437K(472064K)] 419840K->16525K(996352K), 0.0220363 secs] [Times: user=0.02 sys=0.02, real=0.02 secs] 
2021-03-31T15:31:11.544+0800: 12.428: [GC (Allocation Failure) [PSYoungGen: 436277K->31456K(472064K)] 436365K->31560K(996352K), 0.0307199 secs] [Times: user=0.06 sys=0.03, real=0.03 secs] 
2021-03-31T15:31:19.701+0800: 20.585: [GC (Allocation Failure) [PSYoungGen: 451296K->38124K(472064K)] 451400K->38252K(996352K), 0.0416391 secs] [Times: user=0.09 sys=0.00, real=0.04 secs] 
2021-03-31T15:31:27.432+0800: 28.315: [GC (Allocation Failure) [PSYoungGen: 457964K->48005K(472064K)] 458092K->48149K(996352K), 0.0587718 secs] [Times: user=0.24 sys=0.00, real=0.06 secs] 

方式二:

打印详细GC日志并输出到指定文件,并且打印每次GC前后的堆栈信息

-XX:+PrintGC
-XX:+PrintGCDetails
-XX:+PrintGCTimeStamps
-XX:+PrintGCDateStamps
-XX:+PrintHeapAtGC
-Xloggc:./gc.log

结果:

{Heap before GC invocations=1 (full 0):
 PSYoungGen      total 472064K, used 419840K [0x00000000e0000000, 0x0000000100000000, 0x0000000100000000)
  eden space 419840K, 100% used [0x00000000e0000000,0x00000000f9a00000,0x00000000f9a00000)
  from space 52224K, 0% used [0x00000000fcd00000,0x00000000fcd00000,0x0000000100000000)
  to   space 52224K, 0% used [0x00000000f9a00000,0x00000000f9a00000,0x00000000fcd00000)
 ParOldGen       total 524288K, used 0K [0x00000000c0000000, 0x00000000e0000000, 0x00000000e0000000)
  object space 524288K, 0% used [0x00000000c0000000,0x00000000c0000018,0x00000000e0000000)
 Metaspace       used 22318K, capacity 22910K, committed 23168K, reserved 1069056K
  class space    used 2920K, capacity 3095K, committed 3200K, reserved 1048576K
2021-03-31T15:25:31.118+0800: 8.730: [GC (GCLocker Initiated GC) [PSYoungGen: 419840K->16575K(472064K)] 419840K->16663K(996352K), 0.0258389 secs] [Times: user=0.05 sys=0.00, real=0.03 secs] 
Heap after GC invocations=1 (full 0):
 PSYoungGen      total 472064K, used 16575K [0x00000000e0000000, 0x0000000100000000, 0x0000000100000000)
  eden space 419840K, 0% used [0x00000000e0000000,0x00000000e0000000,0x00000000f9a00000)
  from space 52224K, 31% used [0x00000000f9a00000,0x00000000faa2fcb8,0x00000000fcd00000)
  to   space 52224K, 0% used [0x00000000fcd00000,0x00000000fcd00000,0x0000000100000000)
 ParOldGen       total 524288K, used 88K [0x00000000c0000000, 0x00000000e0000000, 0x00000000e0000000)
  object space 524288K, 0% used [0x00000000c0000000,0x00000000c0016028,0x00000000e0000000)
 Metaspace       used 22318K, capacity 22910K, committed 23168K, reserved 1069056K
  class space    used 2920K, capacity 3095K, committed 3200K, reserved 1048576K
}

JVM参数在线检查网址

JVM参数在线检查

你可能感兴趣的:(开发经验,JVM,jvm,java,GC)