了解上面的内容,我们需要先了解JVM中堆的分代的结构
堆的分代结构
JVM Heap
│
┌─────────┴─────────┐
│ │
新生代 (Young) 老年代 (Old)
│
Eden + Survivor
│
S0 + S1(Survivor区分为S0和S1,为了方便复制)
Eden : S0 : S1 = 8 : 1 : 1
新生代GC
新生代主要使用 复制算法(Copying GC)。
流程如下:新建对象-》eden区 -》eden区满-》触发YoungGC-》此时jvm会将survivor From复制到Survivor To;并且这个时候会清空eden区的对象和s0区,然后s0 s1交换角色;
对象晋升到老年代
每一次youngGC,幸存的对象年纪就会加1,当大于等于默认的15次时就会移动到老年代
-XX:MaxTenuringThreshold=15
如果突然有个大对象,导致survivor区满,此时对象会从eden区移动到old区,也称为空间分配担保
老年代GC
老年代对象存活时间更长,因此使用不同算法。
1.标记清除算法(Mark-Sweep)
2.标记整理算法(Mark-Compact)
为什么需要S0和S1?
新生代采用复制算法进行垃圾回收,需要两个 Survivor 区作为 From 和 To。
GC 时将 Eden 和 From 中存活对象复制到 To,然后清空 Eden 和 From,再交换 S0 和 S1 的角色,从而避免内存碎片并提高回收效率
为什么 Eden:S0:S1 = 8:1:1?
JVM 统计发现绝大多数对象生命周期很短,90% 对象在第一次 GC 就会被回收。
因此需要一个较大的 Eden 区减少 Minor GC 频率,而 Survivor 只需要容纳少量存活对象即可。
8:1:1 是 HotSpot 在大量实践中得到的较优比例,既能提高内存利用率,又能减少 GC 次数