用过 JDK9 的同学应该发现了,finalize 方法在 JDK9 中已经被标记为 deprecated,今天探讨一下 finalize 方法。如果没有特别的原因,不要实现 finalize 方法,也不要指望利用它来进行资源回收。因为你无法保证 finalize 什么时候执行,执行的是否符合预期。使用不当会影响性能,导致程序死锁、挂起等。
首先要明白的是为什么会出现 finalize 方法,因为早期一部分程序员是写 C++ 的,仍然保留析构函数释放资源的行为,所以为了让他们平滑的过渡到 Java 并且适应 Java,所以出现了 finalize 方法,用来对象被回收前的一次自我拯救,完成释放资源的操作。那么 Object 的 finalize () 方法的作用是否与 C++ 的析构函数作用相同呢?其实 finalize 方法与 C++ 的析构函数是有很大不同的,析构函数调用确定,而 finalize 是不确定的。重写了 finalize 的对象如果未被引用就会被放置于 F-Queue 队列,而且由一个优先级极底的线程成来执行 finalize 方法,而且方法执行随时可能会被终止。
finalize 的执行是和垃圾收集关联在一起的,一实现了非空的 finalize 方法,就会导致相应对象回收呈现数量级上的变慢,有人专做过 benchmark,大概是 40~ 50 倍的下降。因为,finalize 被设计成在对象被垃圾收集前调用,这就意味着实现了 finalize 方法的对象是个 “特殊公民”, JVM 要对它进行额外处理。finalize 本质上成为了快速回收的阻碍者,可能导致你的对象经过多个垃圾收集周期才能被回收。
下面来看一个示例:
1 | public class Finalization { |
可见 finalize 会拖慢垃圾收集,导致对象堆积,容易导致 OOM,而且使用 finalize 释放资源是不合理的,资源应该是用完立即释放的,或者采用资源池来解决这个问题,而不是依靠被动垃圾回收时触发 finalize 方法。