类不被GC回收,其生命周期由类加载器管理;对象完整经历创建到销毁全过程,全程受GC跟踪干预。

类的生命周期:加载 → 使用 → 卸载(不参与 GC)
类的生命周期由类加载器(ClassLoader)管理,分为加载、链接(验证、准备、解析)、初始化、使用、卸载五个阶段。其中:
- 类加载后常驻方法区(元空间),只要其 Class 对象仍被引用(如被静态变量持有、被正在运行的线程引用),就不会被卸载。
- 类卸载仅发生在特定条件满足时:该类所有实例已被回收、该类的 ClassLoader 已被回收、该类未被任何地方主动引用(包括反射、JNI 等)。此时 JVM 才可能卸载类,释放元空间内存——但这不是 GC 的职责,而是类加载器子系统的清理行为。
- 类本身不会被“垃圾回收”,GC 不处理方法区/元空间中的类数据;但类的卸载会间接影响对象——例如,若某类被卸载,它曾创建的所有对象早已不可达,早已被 GC 处理完毕。
对象的生命周期:创建 → 使用 → 不可达 → 收集 → 终结 → 销毁(GC 全程介入)
对象存在于堆内存中,其每个阶段都与 GC 紧密绑定:
- 创建阶段:new 操作在堆中分配内存,JVM 记录其起始地址与大小;此时对象强可达,GC Roots(如栈帧变量、静态字段)可直接或间接访问它。
- 使用阶段:对象被引用链连接,处于“强可达”状态;GC 在每次运行时都会跳过这类对象。
- 不可达阶段:当所有强引用断开(如赋值为 null、局部变量出作用域、集合移除),且无法从 GC Roots 追溯到该对象时,它被标记为“不可达”——这是 GC 启动回收的前提。
-
收集与终结阶段:GC 触发后,先标记不可达对象;若对象重写了
finalize()方法,会被放入 F-Queue 队列,由 Finalizer 线程异步调用(仅一次,且不保证执行);调用后若仍未复活,则进入待回收队列。 - 销毁阶段:内存真正释放,空间归还给堆;新生代用复制算法快速清空,老年代用标记-整理或标记-清除回收碎片。
GC 如何依据生命周期做决策
垃圾回收器并不“感知”代码逻辑,而是严格依赖对象的可达性状态和分代特征:
- 分代假设起作用:新创建对象进入 Eden 区(新生代),多数很快死亡;GC 优先高频执行 Young GC,快速清理短命对象。
- 晋升机制反映使用阶段长度:对象在 Survivor 区经历多次 GC 仍存活,说明已进入稳定“使用后期”,将晋升至老年代——GC 对老年代更保守,只在必要时触发 Full GC。
- 引用类型改变可达性判定:软引用(SoftReference)对象在内存不足时才被回收;弱引用(WeakReference)在下一次 GC 就被清空;虚引用(PhantomReference)仅用于跟踪回收通知——这些都让开发者能按生命周期意图控制 GC 行为。
实际编码中能观察到的体现
你可以通过日志和工具看到生命周期与 GC 的联动:
立即学习“Java免费学习笔记(深入)”;
- 开启
-XX:+PrintGCDetails,GC 日志里会显示 “PSYoungGen”、“ParOldGen” 等区域回收前后大小,对应对象所处代际变化。 - 使用 JVisualVM 或 JConsole 查看堆内存曲线,对象数量陡降时刻,往往就是某批对象从“使用”滑入“不可达”并被 Young GC 清理的瞬间。
- 定义一个带
finalize()的类并大量创建,会发现 F-Queue 积压、Finalizer 线程繁忙,导致对象延迟回收——这正是生命周期中“终结阶段”拖慢整体销毁节奏的直观表现。


















