JVMJVMjvm

[JVM]理解GC日志

2017-02-09  本文已影响1501人  伤口不该结疤

1. 输出GC日志

通过阅读GC日志,我们可以了解Java虚拟机内存分配与回收策略
先来看一个简单的示例,通过设置VM参数"XX:+PrintGCDetails"就可以打印出GC日志

zhanghuamaodeMacBook-Pro:java zhanghuamao$ java -XX:+PrintGCDetails TestClass
hello
Heap
 PSYoungGen      total 76288K, used 3932K [0x000000076ab00000, 0x0000000770000000, 0x00000007c0000000)
  eden space 65536K, 6% used [0x000000076ab00000,0x000000076aed7240,0x000000076eb00000)
  from space 10752K, 0% used [0x000000076f580000,0x000000076f580000,0x0000000770000000)
  to   space 10752K, 0% used [0x000000076eb00000,0x000000076eb00000,0x000000076f580000)
 ParOldGen       total 175104K, used 0K [0x00000006c0000000, 0x00000006cab00000, 0x000000076ab00000)
  object space 175104K, 0% used [0x00000006c0000000,0x00000006c0000000,0x00000006cab00000)
 Metaspace       used 2630K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 286K, capacity 386K, committed 512K, reserved 1048576K

2. GC日志分析

2.1 新生代Minor GC

先来回顾下垃圾回收算法,通常新生代按照8:1:1(eden space + survivor from space + survivor to space)进行内存划分,新生产的对象会被放到eden space,当eden内存不足时,就会将存活对象移动到survivor区域,如果survivor空间也不够时,就需要从老年代中进行分配担保,将存活的对象移动老年代,这就是一次Minor GC的过程。

新生代

1. 示例代码

/**
 * VM agrs: -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails
 * -XX:SurvivorRatio=8 -XX:+UseSerialGC
 */

public class MinorGCTest {
    private static final int _1MB = 1024 * 1024;

    public static void testAllocation() {
        byte[] allocation1, allocation2, allocation3, allocation4;
        allocation1 = new byte[2 * _1MB];
        allocation2 = new byte[2 * _1MB];
        allocation3 = new byte[2 * _1MB];
        allocation4 = new byte[4 * _1MB];
    }

    public static void main(String[] agrs) {
        testAllocation();
    }
}
Option Description
-verbose:gc 显示GC的操作内容
-Xms20M -Xmx20M 设置堆大小为20M
-Xmn10M 设置新生代的内存空间大小为10M
-XX:+PrintGCDetails 打印GC中的变化
-XX:SurvivorRatio=8 新生代中Eden区域与Survivor区域的大小比值
-XX:+UseSerialGC 在新生代和老年代中使用串行收集器,由于-verbose:gc参数对Parallel Scavenge收集器不起作用,无法显示显示GC的操作内容,因此采用串行收集器

before MinorGC

after MinorGC

2. GC日志

Minor GC日志

2.2 大对象直接进入老年代

1. 示例代码

/**
 * VM agrs: -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails
 * -XX:SurvivorRatio=8 -XX:+UseSerialGC      
 * -XX:PretenureSizeThreshold=3145728
 */

public class TestClass2 {
    private static final int _1MB = 1024 * 1024;
    
    public static void testPretenureSizeThreshold() {
        byte[] allocation;
        allocation = new byte[4 * _1MB];
    }
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        testPretenureSizeThreshold();
    }

}
Option Description
-XX:PretenureSizeThreshold=3145728 所占用内存大于该值的对象直接分配到老年代,3145728为3MB

2. GC日志

大对象直接进入老年代-GC日志

2.3 长期存活的对象进入老年代

1. 示例代码

/**
 * VM agrs: -verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails
 * -XX:SurvivorRatio=8 -XX:+UseSerialGC -XX:MaxTenuringThreshold=1
 */

public class TestClass3 {
    private static final int _1MB = 1024 * 1024;

    public static void testTenuringThreshold() {
        byte[] allocation1, allocation2, allocation3;
        allocation1 = new byte[_1MB / 4];
        allocation2 = new byte[4 * _1MB];
        allocation3 = new byte[4 * _1MB];
        allocation3 = null;
        allocation3 = new byte[4 * _1MB];
    }

    public static void main(String[] agrs) {
        testTenuringThreshold();
    }
}
Option Description
-XX:MaxTenuringThreshold=1 对象晋升为老年代的年龄阀值为1

2. GC日志

MaxTenuringThreshold=1

MaxTenuringThreshold=15

3. 参考

上一篇下一篇

猜你喜欢

热点阅读