JVM中对象生命周期为“创建→可达→不可达→回收”,GC通过可达性分析判定垃圾,分代回收:年轻代用复制算法,老年代用标记-整理或标记-清除,G1按Region收益回收,ZGC/Shenandoah支持并发以降低STW。

对象在JVM堆内存中的生命周期,本质上是“从创建到不可达再到回收”的过程,而垃圾回收(GC)就是围绕这个过程自动执行的内存清理机制。它不依赖程序员手动释放,但其行为直接受代码写法、对象引用关系和JVM配置影响。
对象如何被创建并进入堆中
所有通过 new 关键字、反射、反序列化等方式创建的对象,只要不是局部基本类型或栈上分配的逃逸对象(经JIT优化),默认都分配在堆内存中。对象一诞生,就关联着一个类元数据(存于元空间)、实例数据(字段值)和对象头(哈希码、锁状态、GC分代年龄等信息)。
此时对象处于“存活”状态,只要存在一条从GC Roots出发、可到达它的引用链,它就不会被回收。GC Roots包括:虚拟机栈中引用的对象、本地方法栈中JNI引用的对象、方法区中类静态属性引用的对象、方法区中常量引用的对象、以及正在被同步锁持有的对象。
对象何时变成“垃圾”
判断对象是否死亡,JVM采用可达性分析算法,而非引用计数法(因无法处理循环引用)。当一个对象到任意GC Root都不可达时,即被标记为“可回收”。注意:这不等于立刻被清除——它要经历一次或多次GC周期,尤其涉及分代晋升逻辑。
- 刚创建的对象进入年轻代的Eden区;
- 经过一次Minor GC后仍存活,会被复制到Survivor区,并增加分代年龄;
- 达到阈值(默认15)或Survivor空间不足时,晋升至老年代;
- 老年代对象若长期存活且无引用指向,会在Full GC或G1混合回收阶段被识别为垃圾。
垃圾回收如何实际清理对象
不同代使用不同算法,核心目标是兼顾吞吐、延迟与内存利用率:
- 年轻代普遍用复制算法(如Serial、Parallel、G1的Evacuation),只复制存活对象,天然避免碎片;
- 老年代倾向用标记-整理(如Serial Old、Parallel Old)或标记-清除+局部压缩(如CMS、G1),防止长期运行导致内存碎片化;
- G1则把堆划分为多个Region,按收益优先回收垃圾最多的区域,实现可预测的停顿时间。
每次GC都会引发Stop-The-World(STW),但现代收集器(ZGC、Shenandoah)已支持大部分并发标记与移动,大幅缩短暂停时间。
哪些情况会让对象“意外存活”或延迟回收
看似简单的“不再使用”,在JVM中可能因隐式引用而失效:
- 静态集合类(如static Map)长期持有对象引用,导致内存泄漏;
- 未关闭的资源(IO流、数据库连接)关联着本地句柄,虽Java对象可回收,但底层资源未释放;
- 使用WeakReference/SoftReference/PhantomReference会影响回收时机:弱引用在下次GC必清,软引用在内存不足时才清,虚引用仅用于跟踪对象被回收的时刻;
- 内部类隐式持有外部类引用,若将内部类对象发布到静态上下文,可能延长外部对象生命周期。

















