对象进入老年代的四种形式
- 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的空间和。
由此能够验证,对象达到肯定年龄阈值后,就会进入老年代。