JVM-GC日志详细分析

JVM-GC日志详细分析

1.打印GC日志参数

1.3 基本JVM参数
参数示例 描述说明
-verbose:gc 控制台打印GC参数
-Xms20M 初始堆大小 20M
-Xmx20M 最大堆大小20M 一般情况下-Xms和-Xmx这两个值设为相同大小
-Xmn10M 新生代最大可用值10M
-XX:+PrintGC 触发GC时日志打印
-XX:+PrintGCDetails 触发GC时日志打印详细
–XX:UseSerialGC 串行回收
-XX:SurvivorRatio=8 eden:from:to =8:1:1
-XX:+HeapDumpOnOutOfMemoryErro OOM时生成Dump文件
-XX:NewRatio=2 新生代:老年代 = 1:2

2.GC日志分析

2.1首先运行程序,打印GC参数及日志

设置JVM运行参数

-verbose:gc -Xms20M -Xmx20M  -Xmn10M -XX:+PrintGC -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError -XX:SurvivorRatio=8

运行程序

package com.jzj.jvmtest.gctest;

/**
 * 分析gc日志 主动通过 system.gc触发 垃圾回收
 * 设置 -verbose:gc -Xms20M -Xmx20M -Xmn10M  -XX:+PrintGC -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError  -XX:SurvivorRatio=8
 */
public class SystemGcLog {

    private static final int ONE_MB = 1024 * 1024;

    /**
     * 设置内存20M,最大堆内存20M,新生代10M,那么就剩余10M给老年代
     * 新生代 10M ,Eden:survivor = 8:1, 所以 Eden: 8M, fromSurvivor:1M, toSurvivor:1M, 新生代可用空间就是 8+1 9M
     *
     * @param args
     */
    public static void main(String[] args) {
        //定义1个 byte
        byte[] allocation = new byte[ONE_MB];
        //将 allocation 置为空, 让他成为 垃圾
        allocation = null;
        //主动调用 system.gc() 统计垃圾处理器 回收垃圾
        System.gc();
    }
}

3.分析GC日志

[GC (System.gc()) [PSYoungGen: 3704K->1000K(9216K)] 3704K->1042K(19456K), 0.0010446 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [PSYoungGen: 1000K->0K(9216K)] [ParOldGen: 42K->819K(10240K)] 1042K->819K(19456K), [Metaspace: 3399K->3399K(1056768K)], 0.0034435 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 PSYoungGen      total 9216K, used 246K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 3% used [0x00000000ff600000,0x00000000ff63d890,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 819K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 7% used [0x00000000fec00000,0x00000000fecccc28,0x00000000ff600000)
 Metaspace       used 3406K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 376K, capacity 388K, committed 512K, reserved 1048576K

Process finished with exit code 0
3.1 GC日志的分析
[GC (System.gc()) [PSYoungGen: 3704K->1000K(9216K)] 3704K->1042K(19456K), 0.0010446 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[GC的类别] =》 [gc发生区域]
[PSYoungGen: 3704K->1000K(9216K)] =》 3704K gc发生前,该区域使用的容量,->1000K, gc发生后,该区域使用的容量,(9216K)当前区域的总容量]
外层的3704K->1042K(19456K) =》  3704K->1042K(19456K) 3704K gc前 堆使用的大小, ->1042K gc后,堆使用的容量,19456是堆空间的总容量 
[Times: user=0.00 sys=0.00, real=0.00 secs] =》 user:用户态消耗CPU时间,sys系统内核消耗CPU时间,real从开始到结束使用的时钟时间
  1. GC (System.gc() ) 局部收集 新生代 的模式
    Young GC: 只收集young gen的GC,Young GC还有种说法就叫做 “Minor GC”
    Old GC: 只收集old gen的GC。只有垃圾收集器CMS的concurrent collection 是这个模式
    Mixed GC: 收集整个young gen 以及部分old gen的GC。只有垃圾收集器 G1有这个模式

  2. Full GC 就是收集整个堆,包括新生代,老年代,永久代(在JDK 1.8及以后,永久代会被移除,换为metaspace(元空间))等收集所有部分的模式。

不同的垃圾收集器,触发条件可能不一样

  • 当准备要触发一次 young GC时,如果发现统计数据说之前 young GC的平均大小比目前的 old gen剩余的空间大,则不会触发young GC而是转为触发 full GC (因为HotSpot VM的GC里,除了垃圾回收器 CMS的concurrent collection 之外,其他能收集old gen的GC都会同时收集整个GC堆,包括young gen,所以不需要事先准备一次单独的young GC)
  • 如果有永久代(perm gen) ,要在永久代分配空间但已经没有足够空间时,也要触发一次 full GC
  • 执行System.gc(),heap dump带GC, 其默认都是触发 full GC
  1. PSYoungGen/ParOldGen 表示GC发生的区域, 我们的JVM是哦用的是Server模式,默认的垃圾收集器组合就是Parallel Scavenge垃圾收集器的新生代和使用Parallel old垃圾收集器的老生代JVM-GC日志详细分析
  2. [PSYoungGen: 3704K->1000K(9216K)] =》 3704K gc发生前,该区域使用的容量,->1000K, gc发生后,该区域使用的容量,(9216K)当前区域的总容量]
  3. 外层的3704K->1042K(19456K) =》 3704K->1042K(19456K) 3704K gc前 堆使用的大小, ->1042K gc后,堆使用的容量,19456是堆空间的总容量
  4. [Times: user=0.00 sys=0.00, real=0.00 secs] =》 user:用户态消耗CPU时间,sys系统内核消耗CPU时间,real从开始到结束使用的时钟时间
3.2 GC 堆日志的分析

可以看到堆的 日志如下

Heap
 PSYoungGen      total 9216K, used 246K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
  eden space 8192K, 3% used [0x00000000ff600000,0x00000000ff63d890,0x00000000ffe00000)
  from space 1024K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x00000000fff00000)
  to   space 1024K, 0% used [0x00000000fff00000,0x00000000fff00000,0x0000000100000000)
 ParOldGen       total 10240K, used 819K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  object space 10240K, 7% used [0x00000000fec00000,0x00000000fecccc28,0x00000000ff600000)
 Metaspace       used 3406K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 376K, capacity 388K, committed 512K, reserved 1048576K
  1. PSYoungGen total 9216K, used 246K 堆中 新生代大小,一共9216K也就是9m,9M怎么来的?JVM参数设置的 -Xmn10M,设置的-XX:SurvivorRatio=8 说明 Eden:From:To分别是8:1:1,这样 一共10M的新生代, From和To 只有一块可以用, 所以可使用的内存就是 8+1=9M, 现在用了 246K
  2. eden space 8192K, 3% used Eden区域用了8M
  3. from space 1024K, 0% used to space 1024K, 0% From Survivor和To Survivor都是1M
  4. ParOldGen total 10240K, used 819K 老年代一共10M, 10M怎么来的呢? 设置的 -Xms20M, 堆最大内存20M,其中 -Xmn10M用了10M,那么 老年代就剩余10M了, used 819k,使用了819KB
  5. Metaspace used 3437K, capacity 4496K, committed 4864K, reserved 1056768K

详细看下 Metaspace 细分这么多是干什么的

其中used和capacity是从类加载器的角度来衡量的
而committed和reserved是从操作系统地址空间的角度来衡量

  1. used:是分配给所有类加载器的metachunk中用来存储元数据的部分的大小
  2. capacity:分配给所有类加载器的metachunk的大小,包含每个metachunk的head、used、wasted和current metachunk的free部分
  3. committed:向OS申请的内存中已经分配物理内存的大小,包含VirtualSpaceList中所有node已经commit的部分(也就是非当前node+当前node commit的部分),或者说所有类加载器的capacity+全局空闲链表Chunk Manager+硬件预留HWM margin
  4. reserved:JVM进程虚拟地址空间的部分,像class metaspace默认CompressedClassSpaceSize是1GB,所以reserved就是1GB,日志中的metaspace包含class space和no-class space。
3.2 GC Metaspace元空间分析

JDK 1.7和 JDK 1.8 中,会出现堆内存溢出,并且 JDK 1.8中 PermSize 和 MaxPermGen 已经无效。因此,可以大致验证 JDK 1.7 和 1.8 将字符串常量由永久代转移到堆中,并且 JDK 1.8 中已经不存在永久代的结论。

元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存。因此,默认情况下,元空间的大小仅受本地内存限制,但可以通过以下参数来指定元空间的大小:

-XX:MetaspaceSize,初始空间大小,达到该值就会触发垃圾收集进行类型卸载,同时GC会对该值进行调整:如果释放了大量的空间,就适当降低该值;如果释放了很少的空间,那么在不超过MaxMetaspaceSize时,适当提高该值。
  -XX:MaxMetaspaceSize,最大空间,默认是没有限制的。

除了上面两个指定大小的选项以外,还有两个与 GC 相关的属性:
  -XX:MinMetaspaceFreeRatio,在GC之后,最小的Metaspace剩余空间容量的百分比,减少为分配空间所导致的垃圾收集
  -XX:MaxMetaspaceFreeRatio,在GC之后,最大的Metaspace剩余空间容量的百分比,减少为释放空间所导致的垃圾收集

上一篇:c语言变色圣诞树


下一篇:实战:内存分配与回收策略