堆内存布局

新生代

  • 新生代用于存放新创建的对象;

  • 它分为三个部分:Eden区、Survivor区(通常有两个,称为From和To);

  • 大多数对象首先在Eden区分配,经过一次Minor GC后,存活的对象会被移到Survivor区,经过多次GC后仍然存活的对象会被晋升到老年代。

老年代

  • 老年代用于存放长期存活的对象;

  • 当对象在新生代经过多次GC后仍然存活,会被移到老年代;

  • 老年代的GC频率较低,通常使用Major GC或Full GC进行垃圾回收。

Eden区和Survivor区的功能

Eden区

  • 功能:存放新创建的对象;

  • 特点

    • 大多数对象在Eden区创建;

    • Eden区通常占新生代的较大比例(默认约为80%);

    • 当Eden区满时,会触发Minor GC(新生代垃圾回收)。

Survivor区

  • 功能:存放经过Minor GC后仍然存活的对象;

  • 特点

    • Survivor区分为From和To两个区域,每次Minor GC时交替使用;

    • 对象在Survivor区之间复制,直到达到一定年龄(默认15岁)后晋升到老年代;

    • Survivor区的存在是为了减少直接晋升到老年代的对象数量,从而降低老年代的压力。

新生代垃圾回收的过程

新生代的垃圾回收(Minor GC)通常采用复制算法,具体过程如下:

对象分配

  • 新创建的对象首先分配在Eden区。

Minor GC触发

  • 当Eden区满时,触发Minor GC。

标记存活对象

  • 垃圾回收器会标记Eden区和From Survivor区中所有存活的对象。

复制存活对象

  • 将Eden区和From Survivor区中的存活对象复制到To Survivor区;

  • 如果对象的年龄达到一定阈值(默认15岁),则直接晋升到老年代。

清空Eden区和From Survivor区

  • 复制完成后,清空Eden区和From Survivor区。

交换Survivor区

  • 将From Survivor区和To Survivor区的角色互换,以便下次Minor GC时使用。

Survivor区的设计目的

减少直接晋升到老年代的对象数量

  • 通过Survivor区的多次复制,只有长期存活的对象才会晋升到老年代;

  • 这样可以减少老年代的压力,避免频繁触发Full GC。

优化垃圾回收效率

  • 复制算法只需要复制存活对象,而不需要处理死亡对象,因此效率较高;

  • Survivor区的存在使得复制算法的开销更小。

提高内存利用率

  • Survivor区的设计使得新生代的内存空间得到更高效的利用;

  • 通过多次Minor GC,可以筛选出真正需要长期存活的对象。

相关JVM参数

  • -XX:NewRatio:设置新生代与老年代的比例;

  • -XX:SurvivorRatio:设置Eden区与Survivor区的比例;

  • -XX:MaxTenuringThreshold:设置对象晋升到老年代的年龄阈值。