1
头图
对象进入老年代的四种方式
  • minor gc后,survivor区空间不能容纳全部存活对象
  • 存活对象达到年龄阈值。比如15
  • 大对象
  • 动态年龄判断

这一节,主讲存活对象达到年龄阈值。比如15。

当然,我这里肯定不会设置年龄阈值为15,这多费事啊。我就设置一个2就行。

先上代码:

 public static void _2_year(){
      
        byte[] array1 = new byte[2*_1MB];
        array1 = new byte[2*_1MB];
        array1 = new byte[2*_1MB];


        byte[] array2 = new byte[128*1024];//经过三次GC后,想让这个128K进入老年代

        array1 = null;

        byte[] array3 = new byte[2*_1MB];//第一次minor gc,此时array2指向的对象0岁
        array3 = new byte[2*_1MB];
        array3 = new byte[2*_1MB];

        array3 = null;

        byte[] array4 = new byte[2*_1MB];//第二次minor gc,此时array2指向的对象1岁
        array4 = new byte[2*_1MB];
        array4 = new byte[2*_1MB];
        array4 = null;

        byte[] array5 = new byte[2*_1MB];//第三次minor gc,此时array2指向的对象2岁



    }

JVM参数:

-XX:NewSize=10m -XX:MaxNewSize=10m -XX:InitialHeapSize=20m -XX:MaxHeapSize=20m -XX:SurvivorRatio=8 -XX:PretenureSizeThreshold=10m -XX:MaxTenuringThreshold=2 -XX:+UseParNewGC -XX:+UseConcMarkSweepGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -Xloggc:_2_year_old.log

运行代码后,得到的日志文件:

Java HotSpot(TM) 64-Bit Server VM (25.261-b12) for bsd-amd64 JRE (1.8.0_261-b12), built on Jun 18 2020 06:38:55 by "java_re" with gcc 4.2.1 Compatible Apple LLVM 10.0.0 (clang-1000.11.45.5)
Memory: 4k page, physical 33554432k(1209116k free)

/proc/meminfo:

CommandLine flags: -XX:InitialHeapSize=20971520 -XX:InitialTenuringThreshold=2 -XX:MaxHeapSize=20971520 -XX:MaxNewSize=10485760 -XX:MaxTenuringThreshold=2 -XX:NewSize=10485760 -XX:OldPLABSize=16 -XX:PretenureSizeThreshold=10485760 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:SurvivorRatio=8 -XX:+UseCompressedClassPointers -XX:+UseCompressedOops -XX:+UseConcMarkSweepGC -XX:+UseParNewGC 
0.073: [GC (Allocation Failure) 0.073: [ParNew: 7144K->533K(9216K), 0.0006190 secs] 7144K->533K(19456K), 0.0006854 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
0.074: [GC (Allocation Failure) 0.074: [ParNew: 6837K->550K(9216K), 0.0004091 secs] 6837K->550K(19456K), 0.0004340 secs] [Times: user=0.01 sys=0.00, real=0.00 secs] 
0.075: [GC (Allocation Failure) 0.075: [ParNew: 6837K->0K(9216K), 0.0018452 secs] 6837K->481K(19456K), 0.0018736 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
Heap
 par new generation   total 9216K, used 2212K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)
  eden space 8192K,  27% used [0x00000007bec00000, 0x00000007bee290e0, 0x00000007bf400000)
  from space 1024K,   0% used [0x00000007bf500000, 0x00000007bf500000, 0x00000007bf600000)
  to   space 1024K,   0% used [0x00000007bf400000, 0x00000007bf400000, 0x00000007bf500000)
 concurrent mark-sweep generation total 10240K, used 481K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)
 Metaspace       used 2946K, capacity 4486K, committed 4864K, reserved 1056768K
  class space    used 316K, capacity 386K, committed 512K, reserved 1048576K

此时结合代码和日志分析:

byte[] array1 = new byte[2*_1MB];
        array1 = new byte[2*_1MB];
        array1 = new byte[2*_1MB];


        byte[] array2 = new byte[128*1024];//经过三次GC后,想让这个128K进入老年代

        array1 = null;

此时eden区分配了3个2m对象和1个128k对象。array1置为null。换句说话,就是3个2m对象都是垃圾对象了。

此时如果执行: byte[] array3 = new byte[2*_1MB];

因为eden区空间不足,此时会触发第一次young gc。此时128k对象为0岁。

[ParNew: 7144K->533K(9216K)

GC后,剩下的对象有533k。其中128k是array2指向的对象。剩下400+k是jvm自己创建的未知对象。

接着,不断创建对象,并且保持array2指向128k对象。保证不会被GC 回收,使得128k对象的年龄断增长到2岁。

array3 = null;

        byte[] array4 = new byte[2*_1MB];//第二次minor gc,此时array2指向的对象1岁
        array4 = new byte[2*_1MB];
        array4 = new byte[2*_1MB];
        array4 = null;

        byte[] array5 = new byte[2*_1MB];//第三次minor gc,此时array2指向的对象2岁

ParNew: 6837K->0K(9216K)

经过3次GC后,128K对象已经2岁了。此时新生代的使用空间为0。

concurrent mark-sweep generation total 10240K, used 481K

此时老年代的使用空间为481K。就是一部分未知对象和128k的空间和。

由此可以验证,对象到达一定年龄阈值后,就会进入老年代。


大头菜
41 声望8 粉丝