引用计数法因无法处理循环引用而被JVM弃用:对象A与B互相引用时计数器始终大于0,导致内存泄漏;JVM采用可达性分析法,从GC Roots出发全局遍历,可准确回收整个不可达环。

引用计数法的基本逻辑很简单
每个对象内部维护一个整数计数器,每当有新变量或字段指向它,计数器就 +1;当某个引用被置为 null、离开作用域或重新赋值时,计数器就 -1。一旦计数归零,系统立刻认定该对象“已死”,可立即回收。
循环引用是它无法绕开的硬伤
两个或多个对象彼此持有对方的引用,但外部再无任何活引用指向它们——此时它们实际已不可达、应被回收,但计数器始终大于 0,导致内存泄漏。
- 比如 Parent 持有 Child 的引用,Child 又反向持有 Parent 的引用
- 即使把外部变量全部设为 null,这两个对象的计数器仍各为 1(互相维持)
- JVM 无法识别这种“逻辑死亡”,只能持续保留它们占用的堆空间
Java 虚拟机不采用它的根本原因
不是实现难度高,而是这种缺陷在真实业务中极易发生——尤其在使用监听器、内部类、缓存容器或 ORM 关系映射时,稍不留神就会形成隐式循环引用。JVM 必须保证内存回收的可靠性与一致性,不能容忍“本该回收却一直驻留”的情况。
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
- 所有主流 JVM(HotSpot、OpenJ9 等)都弃用引用计数法
- 取而代之的是 可达性分析算法:从 GC Roots 出发做图遍历,只认“是否能被根到达”,不依赖局部计数
- 哪怕对象间存在环状引用,只要整个环脱离 GC Roots,就能被准确判定并回收
为什么其他语言还能用引用计数?
像 Python、Objective-C(ARC 模式)确实在用,但它们通过额外机制来补救:
立即学习“Java免费学习笔记(深入)”;
- Python 引入了专门的循环检测器(cycle detector),定期扫描并打破引用环
- Objective-C 的 ARC 编译器要求开发者手动标注 weak 或 unowned 来切断环
- Java 选择不做这种妥协,直接用更健壮的全局可达性模型,避免运行时不确定性

















