对象进入老年代的四种方式
- 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的空间和。
由此可以验证,对象到达一定年龄阈值后,就会进入老年代。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。