finalize()方法的作用是为对象在被垃圾回收前提供一次清理非内存资源的机会,但因其执行不可靠、性能差、线程不安全且可能完全不调用,自java 9起已被官方废弃,应改用cleaner或try-with-resources等显式资源管理方式。

Java 中 finalize() 方法的作用,是为对象在被垃圾回收器真正回收前提供一次执行清理逻辑的机会,主要用于释放非 Java 管理的资源(如文件句柄、Socket 连接、本地内存等)。但它不保证被调用,也不保证调用时机,因此不能作为资源管理的主手段。现代 Java 开发中,它已被官方标记为 deprecated(自 Java 9 起),应避免主动使用。
finalize 的核心作用与限制
该方法定义在 Object 类中,子类可重写以实现自定义清理逻辑。JVM 在对象判定为不可达后、内存释放前,可能调用它——但仅“可能”:
- 对象变成 GC Roots 不可达后,若重写了
finalize()且未执行过,会被放入 F-Queue 队列,由低优先级线程异步执行; - 若
finalize()执行中抛出未捕获异常,该异常被吞掉,对象仍会被回收; - 执行完
finalize()后,对象若重新被引用(如赋值给静态变量),可“复活”,但该方法不会再被调用; - JVM 不保证调用顺序、时间,甚至可能全程不触发(尤其内存充足时);
- 它会显著拖慢对象回收速度,增加 GC 压力,影响性能。
为什么不能依赖 finalize 做资源回收
根本原因在于其非确定性:你无法控制它何时运行,也无法确保它一定运行。例如:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
- 一个打开的文件流,若只靠
finalize()关闭,可能在程序耗尽文件描述符后仍未触发回收; - 数据库连接未及时关闭,容易引发连接池耗尽;
- 大量重写
finalize()的对象堆积,会阻塞 F-Queue,拖累整个 GC 流程。
现代 Java 推荐的资源管理方式
替代 finalize() 的方案是显式、可控、可预测的资源管理机制:
-
实现 AutoCloseable 接口 + try-with-resources:适用于流、连接、通道等。JVM 在离开 try 块时自动调用
close(),无需等待 GC; - 显式调用 close() / shutdown() 方法:在业务逻辑明确处释放资源,比如 service 层操作结束后立即关闭;
-
Cleaner(Java 9+):基于虚引用(PhantomReference)的轻量级清理机制,比
finalize()更安全、更可控,适合清理 native 资源; - try-finally 或 try-catch-finally:保障关键清理代码必定执行,尤其在未使用 try-with-resources 的老代码中。
什么情况下可以谨慎考虑 finalize(极少数场景)
仅限于兜底防护,且必须配合显式清理使用:
- 封装了 JNI 调用的类,分配了 C 堆内存(如 malloc),而用户可能忘记调用
close(); - 遗留系统中难以改造的资源持有类,可用
finalize()作最后一道防线(但仍需记录日志告警); - 注意:即便如此,也应优先用 Cleaner 替代,因 Cleaner 不影响 GC 性能,且可注册回调。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










