finalize 方法在现代 java 中已被彻底弃用,因其不可靠、不可控、不安全:gc 不保证调用、无执行时机承诺、易引发 oom、支持对象复活、性能极差,且 jdk 21 已大幅移除底层实现,应改用 try-with-resources 或 cleaner。

finalize 方法在现代 Java 开发中已被彻底弃用,不是因为“不常用”,而是因为它从机制上就不可靠、不可控、不安全。
执行完全不可预测,根本不能用于资源清理
垃圾回收器不承诺调用 finalize,也不承诺调用时机——对象可能永远不被回收,也可能在 GC 压力大时集中触发;JVM 甚至可在 ZGC、Shenandoah 等低延迟收集器中直接跳过 finalization。这意味着:把文件关闭、连接释放写在 finalize 里,等于把系统稳定性交给随机性。
- 无法做超时控制,也无法监控是否执行成功
- 未捕获异常会被静默吞掉,连日志都看不到
- 子类重写时若遗漏 super.finalize(),父类清理逻辑就彻底丢失
严重拖慢 GC,容易引发 OOM
只要类定义了非空的 finalize 方法,所有实例都会被标记为“需终结”,必须经历至少两次 GC 才能真正回收:第一次入 Finalizer 队列,第二次确认未复活后才释放内存。Finalizer 线程是单线程、低优先级、无超时机制,一旦某个 finalize 卡住(比如 IO 阻塞或死锁),整个队列就会积压,后续对象全部无法回收。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- jstat -finalstats 显示 pending-finalize 队列持续增长,是 OOM 的典型前兆
- 实测性能下降可达 40–50 倍,高吞吐场景下尤为明显
- 哪怕只声明一个空的 finalize(),也会让对象销毁变慢数百倍
语义危险,“对象复活”破坏 GC 基础
在 finalize 方法内将 this 赋给静态变量或全局集合,会让本该死亡的对象重新获得强引用——它逃过本次回收,下次 GC 又进队列、再被 finalize、再复活……形成恶性循环。
- 同一对象可能被多次终结,导致 close() 被重复调用、状态错乱、缓存无限膨胀
- Cleaner 等现代方案天然禁止访问原对象,从机制上杜绝复活
- finalize 不是“析构函数”,而是 GC 实现细节暴露出来的风险副产品
官方早已移除支持,替代方案成熟可靠
JDK 9 正式标记为 @Deprecated,JDK 18 起标注 forRemoval = true,JDK 21 已大幅移除底层实现。编译期虽无警告,但运行期可能静默失效——某些 JVM 模式下 finalize 根本不会被调用。
- 关键资源用 try-with-resources + AutoCloseable,作用域结束即释放,确定性强
- 本地资源(如 DirectByteBuffer、文件映射)用 Cleaner,基于虚引用,不阻塞 GC
- 绝对避免在生产代码中重写 finalize,包括空实现
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










