JVM 垃圾回收算法有哪些?

#Java#面试八股

JVM 垃圾回收算法有哪些?

结论先行:垃圾回收只有三种基础算法——标记-清除(mark-sweep)、复制(copying)、标记-整理(mark-compact),其余都是它们的组合与并发化。HotSpot 在此基础上用分代收集(generational collection)把堆切成新生代与老年代,分别套用最合适的算法;并发收集器再叠加三色标记 + 写屏障,把标记过程摊到应用运行期间。

一、三种基础算法

算法步骤优点缺点典型使用者
标记-清除标记存活 → 清除垃圾实现简单,不需要移动对象产生内存碎片,标记与清除效率随堆增大而下降CMS
复制把存活对象复制到另一半空间无碎片,分配只需移动指针空间利用率低,存活率高时复制成本大新生代(Serial/ParNew/Parallel Scavenge)
标记-整理标记存活 → 把存活对象向一端移动无碎片,空间利用率高移动对象要更新所有引用,停顿长Serial Old、Parallel Old
标记-清除:
  [A][ ][B][ ][ ][C]   →  [A][ ][B][ ][ ][C]   空隙留在原地,大对象可能分配失败

复制(Eden + 两个 Survivor):
  [A][B][C][ 垃圾 ][ ]  →  存活对象整体搬到 to 区,from 区整块清空

标记-整理:
  [A][ ][B][ ][C][ ]   →  [A][B][C][ ][ ][ ]   存活对象左移,尾部整块回收

二、分代收集:按对象寿命分区

区域特点采用的算法原因
新生代朝生夕死,存活率低于 10%复制算法存活少,复制成本低;分代假说成立
老年代存活率高,对象大标记-清除或标记-整理存活率高时复制不划算,需要碎片控制

跨代引用用**卡表(card table)记录,老年代对象指向新生代的引用被标记为脏卡,Young GC 时只扫脏卡而不必遍历整个老年代,这就是记忆集(remembered set)**的用途。

三、并发标记的两种屏障

方案屏障类型记录内容使用者
增量更新写后屏障黑色对象新增的引用CMS
原始快照 SATB写前屏障被删除的旧引用G1、Shenandoah

两者的差别在于「重新标记阶段要重新扫描谁」:增量更新扫新增引用,SATB 扫删除引用所指向的对象。SATB 的额外收益是新对象一律视为存活,直接分配到标记结束。

四、用参数验证算法差异

# 新生代复制算法:Eden 与 Survivor 的比例、晋升年龄阈值
java -XX:+UseSerialGC -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -jar app.jar

# 老年代标记-整理:Serial Old / Parallel Old
java -XX:+UseParallelGC -XX:+UseParallelOldGC -jar app.jar

# 标记-清除 + 定期整理:CMS 的碎片治理
java -XX:+UseConcMarkSweepGC \
     -XX:CMSFullGCsBeforeCompaction=5 \
     -XX:+UseCMSCompactAtFullCollection \
     -jar app.jar

CMSFullGCsBeforeCompaction=5 表示执行 5 次不压缩的 Full GC 后做一次带整理的 Full GC,用停顿换碎片空间。

五、常见追问

追问回答要点
为什么新生代用复制算法存活率低,复制量小;代价是浪费一个 Survivor 空间,但整体收益更高
复制算法一定要两倍空间吗不需要,HotSpot 用 Eden + 两个 Survivor(默认 8:1:1),只浪费 10%
标记-清除的碎片怎么解决定期做标记-整理,或换用 G1 这类按 Region 回收、自带整理的收集器
三色标记属于哪种算法它是标记阶段的实现手段,服务于标记-清除/整理,不是独立的回收算法
分代收集会被淘汰吗会淡化。ZGC、Shenandoah 不分代(ZGC 在 JDK 21 引入分代),说明分代只是当前性价比最高的选择

六、并发带来的两个副产品

现象产生原因影响
浮动垃圾(floating garbage)标记完成后、清除进行时,用户线程又产生了新垃圾本轮收不掉,只能留到下一轮,所以收集器要预留空间
并发模式失败(concurrent mode failure)预留空间被耗尽,应用分配速率超过回收速率收集器退化为单线程 Full GC,停顿从毫秒级变成秒级

对策是给收集器留出余量:CMS 用 -XX:CMSInitiatingOccupancyFraction=70 提前启动,G1 用 -XX:G1ReservePercent=10 预留 Region。余量越大越安全,但可用堆越小,这本身就是吞吐与停顿的权衡。

小结

三种算法各有取舍:清除省空间但留碎片,复制快但费空间,整理干净但停顿长。分代是策略层面的组合,三色标记与写屏障是并发化的手段,答题时把这几层分清就不会乱。

笔记加载中…