JVM
-年轻代、老年代学习
- 在
JVM
中,堆又会被细化分为俩个区域- 新生代(Young)1/3
- Eden区 8/10
- From Survivor区(S0) 1/10
- To Survivor区(S1) 1/10
- 老年代(Old)2/3
- 新生代(Young)1/3
MinorGC
- 通常情况下,新创建的对象都会被分配到Eden区(朝生夕死),一些特殊的大对象会直接分配到Old区(可通过参数设置大对象大小的标准)。虽然会优先在
TLAB
分配对象,但其容量其实很小。 - 在经历了
MinorGC
后,Eden区和From Survivor区中存活的对象复制到To Survivor区,然后From和To互换身份。- 如果年龄到达15岁,则进入老年代。
Major GC
- 发生在老年代的垃圾回收过程称作
MajorGC
,一般会伴随着MinorGC
,所以还会有FullGC->STW
。其速度一般会比MinorGC
慢10倍以上。 - 注意点:大对象对虚拟机的内存分配来说是一个坏消息,比这个消息更坏的是遇到一群朝生夕死的大对象,写程序要注意避免。
为什么需要Survivor区,只有Eden区的缺点
代码语言:javascript复制如果没有Survivor,Eden区每进行一次Minor GC,并且没有年龄限制的话, 存活的对象就会被送到老年代。
这样一来,老年代很快被填满,触发Major GC(因为Major GC一般伴随着Minor GC,也可以看做触发了Full GC)。
老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多。
老年代设置空间大或者小不就可以解决上述老年代很快就满了问题吗?
代码语言:javascript复制假如增加老年代空间,更多存活对象才能填满老年代。虽然降低Full GC频率,但是随着老年代空间加大,一旦发生FullGC,执行所需要的时间更长。
假如减少老年代空间,虽然Full GC所需时间减少,但是老年代很快被存活对象填满,Full GC频率增加。
为什么俩个Survivor区一样大呢?
代码语言:javascript复制新生代的垃圾回收器一般选择复制算法进行垃圾回收。同时俩个区一样大也可以解决碎片化问题。
后续补充:
- 晋升老年代默认次数:15,可通过
-XX:MaxTenuringThreshold
设置。- 动态对象:如果在
Survivor
空间中相同年龄所有对象的大小的总和大于Survivor
空间的一半,年龄大于或等于该年龄的对象就可以直接进入老年代,无须等待到15岁。
- 动态对象:如果在
- 空间分配担保
MinorGC
前需检查老年代最大可用的连续空间是否大于新生代所有对象大小总和,如果成立,则MinorGC
是安全的,否则检查HandlePromotionFailure
设置的值,可以则尝试进行MinorGC
,否则进行一次Full GC
。