finalize()方法因导致回收延迟、资源泄漏、线程安全问题及执行顺序不可控,已被jdk 18正式移除,推荐用autocloseable、cleaner或phantomreference替代。

Object 类中的 finalize() 方法本意是为对象提供“临终清理”的机会,但它在垃圾回收过程中会引入一系列难以察觉又后果严重的隐患——这些隐患不是理论风险,而是已在生产环境反复验证的问题。
它让对象回收变慢且不可控
一旦类重写了 finalize(),JVM 会将该对象放入一个特殊的 Finalizer 队列,而不是直接回收。GC 必须先执行 finalize 方法,再等下一轮 GC 才真正释放内存。这意味着:对象生命周期被人为拉长一到两个 GC 周期;Finalizer 线程若繁忙或阻塞(比如在 finalize() 里做 I/O 或等待锁),整个队列就会堆积,拖慢所有后续回收。
它掩盖资源泄漏,还制造新泄漏
- 开发者误以为“反正有 finalize 牢底兜着”,就跳过显式调用
close()或free() - 而
finalize()可能永远不被调用(如 JVM 快速退出、内存未紧张到触发 GC) - 更危险的是:若
finalize()中新建了对象(比如记录日志),又没及时释放,这些新对象可能成为新的内存滞留点
它破坏线程安全与执行顺序
finalize() 由单独的 Finalizer 线程调用,和业务线程完全异步。如果方法内访问共享状态、修改静态变量或尝试加锁,极易引发竞态或死锁。另外,JVM 不保证多个对象的 finalize() 调用顺序——A 对象的 finalize 里引用 B,但 B 可能已被回收,导致 NPE 或状态错乱。
它已从 JDK 生态中实质性退出
JDK 9 开始标记为 @Deprecated,JDK 18 正式移除。所有仍在使用的代码都是技术债。替代方案明确且成熟:对可关闭资源实现 AutoCloseable,配合 try-with-resources;对 native 资源(如 DirectByteBuffer)使用 Cleaner;对需精细控制的场景用 PhantomReference + 引用队列——它们不干扰 GC 主流程,也不依赖“最后时刻”的不确定性。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











