finalize()方法是Object类中被废弃的不可靠清理钩子,仅在对象回收前可能被异步调用一次,不保证时机与执行,现代Java(自Java 9起)已弃用,应改用try-with-resources、Cleaner或显式close()等确定性资源管理方式。

Java 中 finalize() 方法不是推荐使用的资源清理机制,它仅用于理解早期 JVM 如何在对象被回收前提供一次“最后机会”执行清理逻辑,但实际开发中不应依赖或主动使用。它的存在更多是历史设计的遗留,现代 Java(自 Java 9 起)已将其标记为 @Deprecated,并明确建议用更可靠的方式替代。
finalize() 的基本行为和触发条件
该方法定义在 Object 类中,所有类默认继承。当一个对象被 JVM 判定为不可达(即没有 GC Roots 可达路径),且其类重写了 finalize(),JVM 会在真正回收内存前,尝试将该对象放入 finalization 队列,由低优先级的 Finalizer 线程异步调用其 finalize() 方法。
- 只保证最多调用一次——即使对象在
finalize()中“复活”(如赋值给静态变量),后续也不会再触发 - 不保证一定调用:JVM 可能因性能考虑跳过、进程退出前未执行、或长期内存充足而延迟甚至忽略
- 不保证调用时机:可能滞后数秒、数分钟,甚至整个程序生命周期内都不执行
- 调用过程本身会拖慢 GC,增加内存压力,尤其在大量对象重写该方法时
为什么不能把它当作真正的清理手段
核心问题在于非确定性——你无法控制它何时运行,也无法确保它运行。这直接导致资源泄漏风险:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 打开的文件流若只靠
finalize()关闭,可能在系统文件描述符耗尽后仍未释放 - 数据库连接未显式关闭,容易撑爆连接池,引发服务不可用
- 本地内存(如 JNI 分配)若未及时释放,可能造成 native 内存泄漏,JVM 无法感知
- 异常被静默吞掉:
finalize()中抛出未捕获异常,线程终止,但对象照常被回收
如果仅用于教学或兼容旧代码,需注意这些要点
若必须观察其行为(例如调试或理解 GC 流程),应严格限制使用场景,并配合明确的验证逻辑:
立即学习“Java免费学习笔记(深入)”;
- 重写时始终调用
super.finalize()(尽管 Object 默认为空实现) - 避免在
finalize()中执行耗时操作或依赖其他对象状态 - 不要在其中启动新线程、等待锁、或做网络/IO 操作——Finalizer 线程不具备这些保障
- 测试时可调用
System.gc()和System.runFinalization()提示 JVM 尽快处理,但结果仍不保证
真正该用什么替代 finalize()
现代 Java 提供了明确、可控、可预测的资源管理方式:
-
try-with-resources:适用于实现了
AutoCloseable的资源(如FileInputStream、Connection),离开作用域自动关闭 - 显式 close()/shutdown():在业务逻辑结束处主动释放,比如 DAO 层操作完成后立即关闭连接
-
Cleaner(Java 9+):基于虚引用的轻量级清理工具,适合管理 native 资源,比
finalize()更安全、响应更快 - try-finally:在未支持 try-with-resources 的老代码中,确保关键清理代码必定执行

















