引入

对象在新生代中每经历一次垃圾回收, 其年龄就加一, 当年龄达到了一个阈值之后, 下一次垃圾回收就会将该对
象晋升到老年代, 通过-XX:MaxTenuringThreshold=3可以显示的设置对象的年龄阈值的最大值是3, JVM会通过
一块survivor空间(fromspace)的大小对这个年龄阈值进行调整, 但是最大不超过3, 从而可以在survivor空间
使用达到一定的情况下, 使得仍然存活的对象提前晋升到老年代, 这样就可以空出空间, 防止新生代eden可用空
间过小, 从而防止新创建的对象大于eden可用空间的大小, 进而该对象直接在老年代中创建

JVM参数

-verbose:gc
-Xms200m
-Xmx200m
  通过上面两个参数设置堆空间的值为200m
-Xmn50m
  设置新生代空间的大小为50m
-XX:TargetSurvivorRatio=60
  设置当survivor空间(from-space)使用率达到60%的时候就重新调整年龄阈值, 使得该空间内仍然存活的对象
  尽快进入老年代, 根据默认新生代默认比例为8:1:1得出, from-space为5m, 则60%为3m, 则当from-space
  空间使用率达到3m时就会重新计算年龄阈值
-XX:+PrintTenuringDistribution: 打印在survivor空间中对象的年龄情况
-XX:+PrintGCDetails
-XX:+PrintGCDateStamps: 执行GC的时间戳, 即当前时间
-XX:+UseConcMarkSweepGC: 老年代垃圾收集器CMS
-XX:+UseParNewGC: 新生代垃圾收集器
-XX:MaxTenuringThreshold=3: 设置最大的年龄阈值为3, 即JVM调整年龄阈值时不会超过3

测试代码

public class TestClass6 {
  public static void main (String[] args) throws InterruptedException {
    byte[] arr1 = new byte[1024 * 1024];

    test();
    Thread.sleep(1000);
    System.out.println(" 第1次垃圾回收1111111111111111 ");

    test();
    Thread.sleep(1000);
    System.out.println(" 第2次垃圾回收2222222222222222 ");

    test();
    Thread.sleep(1000);
    System.out.println(" 第3次垃圾回收333333333333333 ");

    test();
    Thread.sleep(1000);
    System.out.println(" 第4次垃圾回收444444444444444 ");

    byte[] arr3 = new byte[1024 * 1024];
    byte[] arr4 = new byte[1024 * 1024];
    byte[] arr5 = new byte[1024 * 1024];


    test();
    Thread.sleep(1000);
    System.out.println(" 第5次垃圾回收5555555555555555 ");


    test();
    Thread.sleep(1000);
    System.out.println(" 第6次垃圾回收6666666666666666 ");

  }

  public static void test () {
    for ( int i = 0; i < 40; i ++ ) {
      byte[] arr = new byte[1024 * 1024];
    }
  }
}

分析: 
  <1> test函数中不停的创建对象, 是为了能够触发垃圾回收, 根据上面的计算, eden空间为45m, fromspace
      和tospace均为5m, 在我的计算机中, 创建401m的对象能够触发垃圾回收了, 至于让线程sleep的原因
      是为了能够有一定时间进行停顿
  <2> 初始的时候创建了1M大小的数组, 对于这个数组来说, 在main函数执行完之前都是会存在于堆中的, 然后
      我们一共进行了四次test方法的调用, 其实就是为了能够触发四次的GC, 从而使得这个数组对象的年龄
      从1加到3之后, 第四次的垃圾回收会将年龄为3的这个数组对象放入老年代
  <3> 然后我们创建了三个1M的数组, 这里需要注意的是, 此时eden空间会有3M的对象是一定不会被垃圾回收机
      制回收掉的, 所以当我们调用test方法时, 执行一次垃圾回收, 那么这3M的数组就会被放入fromspace,
      这时候触发了TargetSurvivorRatio=60的选项, 即3M刚好是5M的survivor空间的60%
  <4> 此时会触发JVM调整年龄阈值, 可以从下面的图片分析看到, 阈值被调整到了1
  <5> 再一次执行test, 又一次执行垃圾回收, 此时垃圾回收器会对survivor空间中年龄为1以上及1的所有对象
      进行晋升, 放入老年代

results matching ""

    No results matching ""