JVM 中的分代垃圾回收(Generational Garbage Collection)是一种基于对象生命周期的垃圾回收策略。这个策略假设大多数对象在年轻时就会变得不可达,可以很快被回收,而少数对象会存活较长时间。为了提高垃圾回收的效率,JVM 将堆分为几个代(Generation),并对不同代使用不同的垃圾回收算法。
分代模型
-
年轻代(Young Generation):
- Eden 区:新创建的对象首先分配在 Eden 区。大多数对象在 Eden 区很快会变得不可达并被回收。
- Survivor 区:年轻代通常有两个 Survivor 区(S0 和 S1)。当 Eden 区进行垃圾回收时,仍然存活的对象会被复制到其中一个 Survivor 区(假设 S0),然后 Eden 区会被清空。下一次垃圾回收时,存活的对象会从 S0 复制到 S1(或直接晋升到老年代),依此类推。
-
老年代(Old Generation):
- 当对象在年轻代经历了多次垃圾回收仍然存活,会被晋升到老年代。老年代存储生命周期较长的对象。老年代的垃圾回收频率较低,但每次回收的时间较长。
-
永久代(PermGen)/ 元空间(Metaspace):
- 永久代(PermGen):存储类的元数据、方法、常量池等。从 Java 8 开始,永久代被移除,取而代之的是元空间(Metaspace)。
- 元空间(Metaspace):与堆分配不同,元空间使用本地内存来存储类的元数据。通过减少对堆内存的依赖,元空间改善了内存管理。
垃圾回收器
JVM 提供了多种垃圾回收器,每种垃圾回收器都有不同的策略和特点,可以根据应用的需求进行选择和配置。
年轻代垃圾回收器
-
Serial GC:
- 单线程的垃圾回收器,适用于单核或小内存环境。
- 年轻代采用复制算法,老年代采用标记-整理算法。
-
Parallel GC(也称为吞吐量 GC):
- 多线程的垃圾回收器,适用于多核环境,追求高吞吐量。
- 年轻代采用并行的复制算法,老年代采用并行的标记-整理算法。
-
G1 GC(Garbage First GC):
- 适用于大内存、多核环境,追求低延迟和高吞吐量的平衡。
- 将堆划分为多个区域,采用并行和并发的方式进行垃圾回收。
老年代垃圾回收器
-
Serial Old GC:
- 单线程的老年代垃圾回收器,通常与 Serial GC 配合使用。
- 采用标记-整理算法。
-
Parallel Old GC:
- 多线程的老年代垃圾回收器,通常与 Parallel GC 配合使用。
- 采用并行的标记-整理算法。
-
CMS GC(Concurrent Mark-Sweep GC):
- 并发的老年代垃圾回收器,适用于低延迟的应用。
- 采用标记-清除算法,分为初始标记、并发标记、重新标记和并发清除四个阶段。
调优参数
通过 JVM 参数可以调整垃圾回收的行为,以优化应用的性能:
-
选择垃圾回收器:
-XX:+UseSerialGC # 使用 Serial GC -XX:+UseParallelGC # 使用 Parallel GC -XX:+UseG1GC # 使用 G1 GC -XX:+UseConcMarkSweepGC # 使用 CMS GC
-
调整堆大小:
-Xms<size> # 设置堆的初始大小 -Xmx<size> # 设置堆的最大大小
-
调整年轻代大小:
-Xmn<size> # 设置年轻代的大小
总结
分代垃圾回收通过将堆划分为不同的代,并对不同代使用不同的垃圾回收算法,提高了垃圾回收的效率和应用的性能。选择和配置适当的垃圾回收器,根据应用的需求进行调优,是确保 Java 应用高效运行的重要环节。