0%

为什么要有 GC(GC 出现的背景)

  • 在 C/C++ 等语言中,内存分配(malloc/new)和释放(free/delete)需要手动管理。

  • 手动管理常出错,例如:

    • 内存泄漏:分配了但忘记释放。
    • 悬空指针:释放了但还有引用指向那块内存。
  • GC(垃圾回收)使这类问题自动化处理,减轻程序员负担,但带来性能和暂停(stop-the-world)等代价。

GC 的几种核心算法 / 实现方法及其原理

下面是几种经典或主流 GC 算法的简要原理、优缺点对比:

算法 核心原理 优点 缺点
Mark-Sweep(标记-清除) 从“根”(root)开始标记所有可达对象 → 遍历堆,把未标记的对象清除。 不移动对象 → 指针引用简单;空间利用率还算不错(除碎片问题) 清扫阶段扫描整个堆;产生内存碎片;暂停时间长(必须停止应用线程)
复制算法(Copying / Semi-space / Cheney 的算法) 将堆分为两个半区:一边分配(from-space),满了之后将所有活对象复制到另一半(to-space),然后交换两边。 分配速度快;无需空闲列表管理;自动避免外部碎片;活对象移动后,新生代 gc 开销较低(年轻对象死亡率高) 需要两倍空间(两个半区);复制活对象本身也有成本;指针更新复杂(因为对象被移动)
标记-压缩(Mark-Compact / 标记-整理) 先标记可达对象;然后将可达对象向堆的一端紧凑移动,更新所有指向这些对象的引用。 消除碎片;保持堆连续性,有利于缓存局部性;比传统标记-清除在碎片多时更稳定。 移动对象代价;必须更新所有指针引用;压缩阶段通常暂停时间较长。
分代 GC(Generational GC) 将对象分代(年轻代 / 老年代等),假设大多数对象很快死亡 → 年轻代频繁清理,用复制算法/较快垃圾回收;老年代较少清理,用标记-清除或压缩算法。 减少多数 GC 的暂停时间;年轻代 GC 快且频繁,整体开销低;效率高。 老年代回收仍然可能是高成本;跨代对象指针管理复杂;晋升策略调优不当可能导致老年代“存活”对象过多。

# 深度探索垃圾回收器(GC)