jvm 分代垃圾回收算法
JVM(Java Virtual Machine)中的垃圾回收算法采用了分代收集的策略,即将堆内存划分为多个区域(代),每个区域有不同的垃圾回收策略。分代垃圾回收模型的核心思想是不同生命周期的对象有不同的回收方式。JVM的堆一般分为三个主要区域:年轻代(Young Generation)、老年代(Old Generation)和永久代(PermGen)(在JVM 8及之后的版本,永久代被元空间(Metaspace)取代)。
1. 年轻代(Young Generation)
年轻代用于存放新创建的对象。年轻代的回收通常使用Minor GC(小型垃圾回收)。
年轻代内部通常分为三个区域:
- Eden Space:存放新创建的对象。
- Survivor Space(S0 和 S1):存放从Eden或其他Survivor空间中复制过来的幸存对象。
年轻代的垃圾回收会发生在Eden区和Survivor区满的时候。垃圾回收时,所有存活的对象会从Eden区复制到一个Survivor区,另一个Survivor区会被清空。这个过程称为复制算法(Copying)。
2. 老年代(Old Generation)
老年代用于存放生命周期较长的对象。当年轻代中的对象经历了多次垃圾回收后,仍然存活,则会被晋升到老年代。老年代的垃圾回收称为Major GC(大型垃圾回收),通常会暂停整个应用程序的运行,因此它的回收成本较高。
老年代的垃圾回收通常采用标记-清除(Mark-Sweep)或标记-整理(Mark-Compact)算法。标记-清除算法会标记存活的对象,然后清理掉不再需要的对象;而标记-整理算法除了标记和清理外,还会整理存活对象,避免内存碎片。
3. 永久代(PermGen)/元空间(Metaspace)
在JVM 8之前,类的元数据(如类信息、方法等)存放在永久代。永久代的大小是固定的,如果该区域的内存耗尽,JVM会抛出java.lang.OutOfMemoryError: PermGen space
错误。
从JVM 8开始,永久代被元空间(Metaspace)取代。元空间将类的元数据存储在本地内存中,而不是JVM堆内存中,因此可以动态扩展,不再受到固定大小的限制。
分代垃圾回收的关键算法:
- 复制算法(Copying):用于年轻代的垃圾回收。通过将存活对象复制到另一区域来回收空间,通常将对象从Eden区复制到一个Survivor区,然后清空Eden区。
- 标记-清除(Mark-Sweep):用于老年代的回收。标记所有存活对象,然后清除不再使用的对象。
- 标记-整理(Mark-Compact):与标记-清除类似,但在清除的同时,整理存活对象,避免内存碎片。
总结:
JVM的分代垃圾回收算法主要通过将堆内存分为年轻代和老年代来优化垃圾回收的性能,分别使用不同的回收策略(复制算法、标记-清除、标记-整理)来处理不同生命周期的对象。通过这种方式,JVM能够高效地管理内存并减少垃圾回收带来的性能开销。