今天给大家带来的文章:JVM分代年龄为何是15次?能设置为16吗?希望对同学们有所帮助。
文章目录
Java 面试专栏
JVM区域
JVM分代年龄为何是15次?能设置为16吗?
了解堆内存划分
了解JVM垃圾回收机制
了解对象头的存储结构
一、堆内存划分
在JVM的堆(Heap)内存里面,分为伊甸园区(Eden space)、Survivor(From、TO)区、老年代(Old generation)。
二、GC
当我们在Java里面使用new关键字创建一个对象的时候,JVM会在Eden区分配一块内存来存储这个对象。当Eden区的内存空间不足的时候,就会触发Minor GC(新生代GC)进行对象回收。那些因为存在引用关系而无法回收的对象,JVM会把他们转移到Survivor区。
Survivor内部分为From区和To区,刚从Eden区转移过来的对象会分配到From区,每经历一次Young GC,这些没被回收的对象就会在From区和To区来回移动,每移动一次,这个对象的GC年龄就加1。默认情况下GC年龄达到15的时候,JVM就会把这个对象移动到Old generation。
三、对象头的存储结构
一个对象的GC年龄,存储在对象头里面。在HotSpot虚拟机里,对象在堆内存中的存储布局可以划分为三个部分:对象头(Header)、实例 数据(Instance Data)和对齐填充(Padding)。下面我们将从这三个方面认识对象的内存布局。
3.1 对象头
对象头主要包含两部分信息:第一类是用于存储对象自身的运行时数据,对象头的另外一部分是类型指针,即对象指向它的类型元数据的指针,Java虚拟机通过这个指针来确定该对象是哪个类的实例。
那么我们重点讲解下用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。官方称这部分数据为 “Mark Word” ,如下图所示。
3.1.1、对象分代年龄
其中的age(对象分代年龄),可以看到它的存储空间是4bit,4bit最大值上限是十进制的15。
这里科普一下bit:
比特是英文binary digit的缩写。位(bit) 来自英文bit,音译为“比特”,表示二进制位。位是计算机内部数据储存的最小单位,11010100是一个8位二进制数。一个二进制位只可以表示0和1两种状态(2^1)。
二进制转换十进制:
十进制
二进制
4bit
8bit
1
1
0001
00000001
2
10
0010
00000010
3
11
0011
00000011
4
100
0100
00000100
5
101
0101
00000101
6
110
0110
00000110
7
111
0111
00000111
8
1000
1000
00001000
9
1001
1001
00001001
10
1010
1010
00001010
11
1011
1011
00001011
12
1100
1100
00001100
13
1101
1101
00001101
14
1110
1110
00001110
15
1111
1111
00001111
16
10000
超出范围
00010000
四、精简回答
4.1、GC方面
在使用new创建对象时,JVM会在Eden区分配一块内存来存储这个对象。当Eden区的内存空间不足的时候,就会触发Minor GC(新生代GC)进行对象回收。那些因为存在引用关系而无法回收的对象,JVM会把他们转移到Survivor区。
Minor GC非常频繁,因此需要把Survivor区一直回收不了的数据,放到Old区,默认是S0、S1移动达到15次(GC年龄达到15)。
4.2、对象头设置
HotSpot虚拟机对象头里用4bit来存储GC分代年龄,而4个bit能够存储的最大值是15。从这个角度来说, JVM分代年龄之所以设置成15次,是因为它最大能够存储的数值就是15。
因此我们说,虽然JVM提供了参数来设置分代年龄的大小,但是这个大小不能超过15,也就不能设置为16。
4.3、从设计角度来看
从设计角度来看,当一个对象触发了最大值15次Minor GC(新生代GC),还没有办法被回收,就只能移动到Old区。
另外,设计者还引入了动态对象年龄判断的方式来决定把对象转移到Old区,不管这个对象的GC年龄是否达到15次,只要满足动态年龄判断的依据, 也同样会转移到Old区。
总结
本章节从GC方面、对象头设置、Minor GC(新生代GC)设计角度这3个方面,解析了JVM分代年龄为何是15次。
有兴趣的同学还可以扩展下,Minor GC(新生代GC)、Full GC的频率,什么条件触发?有哪些垃圾回收算法?等等。