Object.finalize()会显著拖慢GC速度,因其强制对象经历两次GC才能回收、Finalizer线程串行处理易阻塞队列、可能引发对象复活并破坏GC并发性,且自JDK9起已被弃用。

Object.finalize() 会显著拖慢 GC 速度,核心原因不是方法体本身多耗时,而是它强行改变了 JVM 垃圾回收的正常流程,引入额外阶段、串行阻塞和不可控延迟。
触发两次标记与延迟回收
重写了 finalize() 的对象,在第一次可达性分析判定为不可达后,不会被立即回收,而是被放入 F-Queue 队列,等待 Finalizer 线程执行 finalize()。只有等这个方法“返回”(不保证执行完),对象才可能在下一次 GC 中被真正回收。这意味着: - 每个带 finalize 的对象至少要经历两次 GC 才能释放内存 - 第一次 GC 后对象仍驻留堆中,占用空间并可能提前晋升到老年代 - 老年代堆积加快,触发更昂贵的 Full GC 频率上升
Finalizer 线程串行处理且不可控
Finalizer 线程是单线程、低优先级的守护线程,所有待终结对象必须排队由它依次处理: - 任一对象的 finalize() 执行缓慢(如 I/O 等待、死循环、复杂计算),就会卡住整个队列 - 后续对象无法被清理,F-Queue 持续积压,堆内存只增不减 - 极端情况下,一个失控的 finalize() 可导致内存回收子系统实质瘫痪
破坏 GC 并发与确定性
现代 GC(如 G1、ZGC)依赖快速、可预测的对象生命周期管理: - finalize() 让对象“复活”成为可能(通过重新赋值 this 引用),打破 GC 对对象状态的假设 - JVM 无法在并发标记阶段安全地处理 finalizable 对象,被迫退回到更保守、更耗时的处理路径 - 异常在 finalize() 中被静默吞掉,错误无法暴露,资源泄漏难以排查,间接加剧内存压力
已被淘汰的设计,没有优化价值
finalize() 在 JDK 9 中被标记为 @Deprecated,JDK 18 彻底移除: - 它不是一种“可调优”的机制,而是一个结构性缺陷 - 任何性能优化(比如精简逻辑)都治标不治本,无法解决双阶段回收和串行瓶颈 - 替代方案 Cleaner 和 PhantomReference 基于引用队列,由 ReferenceHandler 线程统一调度,不干扰主 GC 流程,可控性强、开销极低

















