Java垃圾回收基于可达性分析,从GC Roots出发标记存活对象,未被触达的即为垃圾;不采用引用计数法因无法解决循环引用;System.gc()仅是建议且不可靠;分代回收依对象生命周期差异采用不同算法。

Java中的垃圾回收(GC)不是“定时清理内存”的后台服务,而是JVM基于对象可达性自动判定并回收堆中无用对象的机制——它不看对象“有没有被new出来”,只看“还有没有活引用能触达它”。
怎么判断一个对象是不是垃圾?关键在GC Roots和可达性分析
JVM不会扫描每个对象去问“你还用不用”,而是从一组可信起点(GC Roots)出发,顺着引用链往下找。所有能被这条链触达的对象都算“活着”,其余全是垃圾。
常见的GC Roots包括:
⚠️ 注意:局部变量一旦离开作用域(比如方法return或抛异常),其引用立即失效,对应堆对象可能立刻变成垃圾——哪怕你没显式赋值为null。
立即学习“Java免费学习笔记(深入)”;
为什么不用引用计数法?循环引用是硬伤
引用计数法听起来简单:每个对象维护一个计数器,+1/-1,归零就回收。但它在Java中根本没被采用,原因很实在:
- 两个对象互相持有对方引用(比如
A.b = new B(),B.a = new A()),计数器永远不为0 - 多线程下计数器增减非原子操作,需额外同步开销
- 每个对象都要存一个整数,堆内存浪费明显
所以HotSpot JVM全程使用可达性分析,彻底绕过循环引用陷阱。
本文档主要讲述的是关于Objective-C手动内存管理的规则;在ios开发中Objective-C 增加了一些新的东西,包括属性和垃圾回收。那么,我们在学习Objective-C之前,最好应该先了解,从前是什么样的,为什么Objective-C 要增加这些支持。有需要的朋友可以下载看看
System.gc()到底管不管用?
System.gc()只是向JVM发出“建议尽快GC”的信号,不保证执行,更不保证何时执行。在生产环境调用它,往往适得其反:
- 触发Full GC概率高,造成明显STW(Stop-The-World)停顿
- 干扰JVM自适应策略,比如G1或ZGC的预测性回收节奏
- 某些JVM(如开启
-XX:+DisableExplicitGC)会直接忽略该调用
真正需要控制GC时机的场景(如批处理结束前释放资源),应优先考虑对象复用、池化或明确的try-with-resources,而不是依赖System.gc()。
年轻代和老年代的回收逻辑为什么完全不同?
分代假设(Mostly-Allocations-Are-Short-Lived)决定了不同区域用不同算法:
- 年轻代:99%以上对象朝生暮死 → 用复制算法(Eden + S0/S1),快且无碎片
- 老年代:对象存活久、空间大、不能总复制 → 用标记-整理(如Serial Old)或标记-清除+压缩(如CMS已废弃,G1/ZGC靠Region+并发标记)
一个对象从new到进入老年代,要经历:Eden分配 → Minor GC后幸存 → 在Survivor间来回拷贝(默认15次)→ 达到阈值或过大直接晋升(PretenureSizeThreshold)。这个过程不是凭空发生,而由JVM根据实际晋升率动态调整。
GC不是黑盒魔法,它的行为直接受代码中引用生命周期、对象大小、分配速率影响。写Java时真正该关注的,从来不是“怎么手动触发GC”,而是“我创建的引用,在哪一刻真正断开了”。









