Java中的垃圾回收

作者:zhangyunlong 发布时间: 2024-09-13 阅读量:5 评论数:0

垃圾回收算法

算法

原理

优点

缺点

标记-清除算法

首先遍历堆中的对象, 标记出所有存活的对象, 接着清除未标记的对象

实现简单, 能处理堆中所有的对象

标记和清除过程中会产生内存碎片, 影响后续内存分配效率

标记-整理算法

首先标记出内存中所有存活的对象, 然后将存活的对象整理到一边, 最后清除未标记的对象

避免了内存碎片问题

整理阶段需要移动对象, 导致额外开销

复制算法

将内存分为两部分, 每次只使用其中一半, GC时将存活的对象复制到另一半, 清除原区域中的所有对象

无需处理内存碎片, 分配效率高

浪费了一半的空间

  • 分代收集算法

    • 将堆分为新生代和老年代, 分别使用不同的垃圾回收算法

    • 新生代一般使用复制算法

    • 老年代一般使用标记-清除 或 标记-整理算法

    • 充分利用对象的生命周期长短不一的特点

  • 并行垃圾回收算法

    • 使用多个线程同时进行垃圾回收, 提高回收效率

    • 主要包括并行标记-清除和并行复制

主流垃圾收集器

收集器

年轻代

老年代

特点和定位

Serial(串行)

复制算法

标记-整理算法

最基础, 单线程的收集器, 适用于内存较小, CPU核数较少的环境

ParNew(并行)

复制算法

标记-整理算法

Serial的多线程版本.

年轻代并行收集, 老年代通常配合Serial Old(单线程).

ParallelScavenge

复制算法

标记-整理算法

注重吞吐量, 目的是达成一个可控的自适应GC时间

CMS

复制算法

标记-清除算法

追求最短停顿时间.

老年代使用并发的标记-清除算法, 会产生内存碎片.

G1

复制算法

标记-整理算法

化代分区的收集器. 整体看是标记-整理, 局部(Region)看是复制, 它将堆划分为区域, 实现了可预测的停顿时间.

  • 年轻代的主流选择

    • 几乎所有经典GC在年轻代都选择复制算法

    • 因为年轻代的对象朝生夕死, 存活率极低, 复制算法只需要复制少量存活对象, 效率极高, 且无内存碎片

  • 老年代的策略区别

    • Parallel和Serial采用标记整理, 目的是消除内存碎片, 适用于存活率高的老年代

    • CMS采用标记清除, 因为它可以并发快速清理, 锁定停顿时间, 但是会产生内存碎片

    • G1虽然将堆划分为Region区, 但是Region区之间的GC还是复制(或整理)行为, 最终目的是消除碎片, 其算法倾向于标记-整理

  • ZGC

    • 现代的低延迟收集器

    • 不严格区分新生代和老年代

    • 基于Region技术, 核心算法通常属于标记-整理或者复制的变体

    • 重点是并发整理, 实现毫秒级停顿

评论