垃圾回收日志分析

  • JVM参数

    -verbose:gc             输出GC的所有信息
    -Xms20m                 设置堆的最小为20m
    -Xmx20m                 设置堆的最大为20m
    -Xmn10m                 设置堆中新生代为10m
    -XX:+PrintGCDetails     开启打印GC详细信息到控制台的功能
    -XX:SurvivorRatio=8     设置新生代中eden空间和survivor空间的比例是8:1:1
    分析: 由以上JVM参数可得, 我们设置了堆的大小为20m, 新生代的大小为10m, 新生代中eden空间为8m, 两个
        survivor空间均为1m, 除去新生代后便是老年代, 所以老年代的空间为10m
    
  • 代码一(无GC)

    public class TestClass1 {
      public static void main (String[] args) {}
    }
    分析: 我们定义了一个TestClass1类, 并在里面定义了一个main方法, 然后执行main方法, 此时查看输出如下
        图所示
    

  • 代码二(MinorGC)

    public class TestClass1 {
      public static void main (String[] args) {
          int size = 1024 * 1024;
          byte[] arr1 = new byte[2 * size];
          byte[] arr2 = new byte[2 * size];
          byte[] arr3 = new byte[3 * size];
    
      }
    }
    分析: 设置大小size为1024*1024, 那么当我们创建字节数组并且为size大小的时候, 则该字节数组的大小为
        1M, 根据代码可得, 我们创建了7M大小的即7168K大小的字节数组, 同时会在堆内存中占据7168K, 加上
        之前的分析可得, 虚拟机默认会使用2009K, 所以7168+2009=9177已经大于了eden空间8192K的大小,
        此时会执行垃圾回收, 如下图所示: 
    
        补充: PSYoungGen: Parallel Scavenge (新生代垃圾收集器)
              ParOldGen: Parallel Old (老年代垃圾收集器)
    

  • 代码三(FullGC)
    public class TestClass1 {
      public static void main (String[] args) {
          int size = 1024 * 1024;
          byte[] arr1 = new byte[2 * size];
          byte[] arr2 = new byte[3 * size];
          byte[] arr3 = new byte[3 * size];
      }
    }
    分析: 在上一个代码的情况下将arr2的大小设置为3M, 此时会触发Full GC, 我们先不用去考虑为什么会触发该
        GC, 下面的分析只是对Full GC日志的讲解
    

  • 代码四(验证JVM中新生代容纳不下新创建的对象时, 新创建的对象将会直接在老年代中诞生)
    public class TestClass2 {
      public static void main (String[] args) {
          int size = 1024 * 1024;
          byte[] arr1 = new byte[8 * size];
      }
    }
    分析: 参数仍然是之前那几个, 也就是说新生代中Eden空间为8M, 两个Survivor空间均为1M, 总的来说新生代
       中可用空间是9M, 此时我们创建的是8M的数组对象, 新生代是不能存放下如此大的对象的, 所以会直接晋
       升到老年代, 如下图所示
    

results matching ""

    No results matching ""