# 15. Java Finalize 方法的作用是什么?为什么不推荐使用?
# 标准答案
finalize()
方法是 Java 对象的终结(finalization)机制,在对象被 GC 之前由 JVM 进行回调,通常用于释放非 Java 资源(如文件句柄、网络连接)。但 finalize()
存在不确定性、性能开销大、容易导致内存泄漏,因此 不推荐使用。JDK 9 之后已被废弃,JDK 18 彻底移除。推荐使用 try-with-resources(AutoCloseable
)或显式 close()
方法 进行资源管理。
# 答案解析
# finalize()
的作用
finalize()
是 Object
类的一个方法,子类可重写它,在对象被垃圾回收前执行清理逻辑:
@Override
protected void finalize() throws Throwable {
System.out.println("Finalizing...");
}
1
2
3
4
2
3
4
但 JVM 何时调用 finalize()
不可控,它不会立即释放资源,因此不是可靠的清理机制。
# finalize()
存在的问题
- 不确定性:GC 运行不可预测,
finalize()
可能长时间不执行,甚至永远不执行。 - 影响 GC 性能:JVM 需要专门的
Finalizer
线程管理finalize()
队列,拖慢 GC 速度。 - 可能导致对象复活:在
finalize()
内部如果将this
赋值给静态变量,对象会 重新变成可达,影响 GC。 - 已被废弃:JDK 9 标记为
@Deprecated
,JDK 18 彻底移除。
示例:finalize()
造成对象复活
public class FinalizerEscape {
static FinalizerEscape instance;
@Override
protected void finalize() throws Throwable {
instance = this; // 复活对象
}
public static void main(String[] args) throws InterruptedException {
instance = new FinalizerEscape();
instance = null;
System.gc(); // 触发 GC
Thread.sleep(1000);
System.out.println(instance != null); // true,对象复活
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 更好的替代方案
- 使用
try-with-resources
(AutoCloseable
机制):class Resource implements AutoCloseable { @Override public void close() { System.out.println("Resource closed"); } } try (Resource res = new Resource()) { // 使用资源 } // 自动调用 close()
1
2
3
4
5
6
7
8
9
10 - 手动
close()
方法:class CustomResource { void close() { System.out.println("Manually releasing resources"); } } CustomResource res = new CustomResource(); res.close(); // 显式释放资源
1
2
3
4
5
6
7
8 - 使用
PhantomReference
进行对象回收监控:ReferenceQueue<Object> queue = new ReferenceQueue<>(); PhantomReference<Object> ref = new PhantomReference<>(new Object(), queue);
1
2
# 常见错误
- 误以为
finalize()
是 GC 的一部分,实际它运行在Finalizer
线程,不会加速 GC。 - 依赖
finalize()
释放资源,可能导致资源泄漏,正确方式是try-with-resources
或close()
。 - 在
finalize()
里抛异常,不会传播,可能导致对象无法被回收。
# 最佳实践
- 完全避免
finalize()
,使用try-with-resources
或close()
。 - 监控 Finalizer 队列,避免 GC 受影响:
jcmd <pid> GC.finalizer_info
1 - 确保资源及时释放,避免资源泄漏和 OOM。
# 深入追问
- 为什么
finalize()
的执行时间无法预测? PhantomReference
如何替代finalize()
进行资源管理?try-with-resources
在 JDK 7 之前如何实现?
# 相关面试题
finalize()
、close()
、try-with-resources
的区别?- Java 里有哪些资源管理方式?
PhantomReference
的应用场景?- 为什么 JDK 18 移除了
finalize()
?