GC 算法分两层:判断对象死亡的算法,和回收内存的算法。
判定存活性:引用计数法实现简单(Python 使用),但解决不了循环引用;Java 用可达性分析,从 GC Roots 出发遍历引用链,不可达的对象判定为可回收,再通过 finalize(已废弃)与两次标记确认死亡。
回收算法有三种基础算法:标记-清除,标记出存活对象后清除其余,简单但产生内存碎片,且效率随存活率下降;标记-复制,把存活对象复制到另一半内存,无碎片、分配高效,代价是可用内存减半——新生代对象朝生夕死,非常适合,所以新生代用 Eden + 两个 Survivor 做复制回收;标记-整理,标记后把存活对象向一端移动再清理边界外内存,无碎片但移动成本高,适合存活率高的老年代。
实际 JVM 采用分代收集理论,组合使用:新生代用复制,老年代用标记-清除或标记-整理。现代收集器(G1、ZGC)进一步引入分区(Region)与增量回收的思路。
追问方向:跨代引用如何避免全堆扫描?(记忆集/卡表)对象何时晋升老年代?
(约 340 字)