为什么 Java 新生代被划分为 S0、S1 和 Eden 区?

Sherwin.Wei Lv7

回答重点

主要是为了提高新生代内存的利用率。

扩展知识

详细分析

因为新生代对象朝生夕死的特性,适合复制算法。按正常思路将新生代一分为二,划两块区域,每次只使用其中一个,GC 后将存活的复制到另一个区域,然后清理老区域非存活对象,这样替换使用两块区域可以避免内存碎片的存在。

但如果一分为二的话,空间利用率只有一半了(每次分配对象只能占据一半的内存大小),这样不太划算。

image.png

基于这点,定义了三个区域,Eden 区和两个 Survivor 区,Eden 区 + 1 个 Survivor 区可以比二分之一大,提升利用率,默认 Eden 占 80% ,一个 Survivor 占 10%。

image.png

然后利用两个 Survivor 来交替接收 gc 后存活的对象。

比如当前用 Eden + s0 两块区域,gc 的时候将存活的对象拷贝至 s1,然后清理 Eden 和 s0,接着使用 Eden + s1 作为新的对象分配区域。

image.png

后面 gc 后,把存活的对象拷贝至 s0,就这样往复使用两个 Survivor 区即可,这种划分手段就提升了内存的利用率。

并且程序可以根据自身的特性调整 Eden 区和 Survivor 区的比例,默认 8:1:1。

如果单个 Survivor 放不下 GC 存活的对象怎么办?

老年代兜底。

也就是说如果 Survivor 放不下存活的对象,那么超出的对象直接晋升到老年代。

如果老年代剩余的空间也放不下这些存活的对象怎么办?

如果是 CMS 垃圾回收器,则会触发 CMS 回收。如果 CMS 回收不足以回收足够的空间,会触发 Full GC(Serial Old 回收器)。

如果是 G1 垃圾回收器则会触发 Mixed GC。

目录
为什么 Java 新生代被划分为 S0、S1 和 Eden 区?