finalize 方法在现代 Java 中已不推荐使用,自 Java 9 被标记为 @Deprecated,Java 21 中 JVM 不再保证调用且默认禁用;因其非确定性、性能开销大、异常被吞、线程不安全等缺陷,无法可靠回收资源;应改用 try-with-resources 或 Cleaner 等确定性机制。

finalize 方法在现代 Java 中已不推荐使用,不能依赖它来处理资源回收。自 Java 9 起,finalize() 被标记为 @Deprecated;Java 18 进一步明确其“即将移除”;Java 21 中虽仍存在,但 JVM 不再保证调用,且默认禁用(可通过 -XX:+ExplicitGCInvokesFinalize 启用,但不建议)。
为什么 finalize 无法可靠解决资源遗留问题
该方法由垃圾回收器(GC)在对象被回收前**非确定性地、最多调用一次**,存在严重缺陷:
- 调用时机不可控:GC 何时运行、是否运行、是否回收某对象,完全不确定;可能程序结束都未触发
- 执行开销大:启用 finalization 会显著拖慢 GC,影响整体性能
- 异常被吞:若
finalize()抛出未捕获异常,JVM 仅静默忽略,资源仍泄漏 - 线程不安全:
finalize()在专用 Finalizer 线程中运行,与业务逻辑并发,易引发竞态 - 无法替代显式清理:文件句柄、网络连接、数据库连接等必须主动关闭,不能等 GC
正确替代方案:用 try-with-resources 和 Cleaner
Java 提供了更安全、可控的资源管理机制:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
try-with-resources:适用于实现
AutoCloseable的资源(如FileInputStream、Connection),编译器自动插入close()调用,确保及时释放 - Cleaner(Java 9+):轻量级、无堆内存依赖的清理工具,用于处理非堆资源(如直接内存、本地句柄)。它不依赖 GC 周期,可注册清理动作,在对象不可达时异步执行(但仍不保证立即)
示例(Cleaner 使用):
立即学习“Java免费学习笔记(深入)”;
private static final Cleaner cleaner = Cleaner.create();
private final Cleaner.Cleanable cleanable;
// 构造时注册清理逻辑
public MyResource() {
this.cleanable = cleaner.register(this, new ResourceCleanup(this));
}
private static class ResourceCleanup implements Runnable {
private final MyResource resource;
ResourceCleanup(MyResource resource) { this.resource = resource; }
public void run() { resource.releaseNativeResources(); }
}
如果必须兼容旧代码,注意 finalize 的基本写法
仅限维护遗留系统且无法升级时参考。务必遵守以下原则:
- 始终调用
super.finalize()(若父类有实现) - 只做资源释放,不做复杂逻辑或重新引用
this(否则可能阻止 GC) - 用
try-catch包裹所有操作,防止异常中断清理流程 - 绝不假设它会被调用——所有关键资源仍需显式释放
错误示范:protected void finalize() throws Throwable { close(); }
正确写法(仅作说明,不推荐):protected void finalize() throws Throwable { try { close(); } finally { super.finalize(); } }
总结:别用 finalize,改用确定性资源管理
资源泄漏的根本解法是「谁获取,谁释放」。优先选择:
✅ try-with-resources(标准 I/O、JDBC)
✅ 显式调用 close() / shutdown()(配合 finally 或 try-catch)
✅ Cleaner(处理 JNI、DirectByteBuffer 等非堆资源)
❌ finalize() —— 它不是兜底方案,而是历史包袱

















