finalize真的那么不堪?

是的,真的那么不堪!

业界实践一再证明java.lang.Object中的finalize不是个好的办法,在Java 9中,甚至明确将它标记为deprecated!如果没有特别的原因,不要实现finalize方法,也不要指望利用它来进行资源回收。为什么呢?简单说,你无法保证finalize什么时候执行,执行的是否符合预期。相反使用不当会影响性能,导致程序死锁、挂起等。

finalize的执行是和垃圾收集关联在一起的,一旦实现了非空的finalize方法,就会导致相应对象回收呈现数量级上的变慢,有人专门做过benchmark,大概是40-50倍的下降。

因为,finalize被设计成在对象被垃圾收集前调用,这意味着实现了finalize方法的对象是个“特殊公民”,JVM要对它进行额外处理。也就是说,finalize成为了快速回收的阻碍者,可能导致你的对象经过多个垃圾收集周期才能被回收。

有人也许会问,我用System.runFinalization()告诉JVM积极一点,是不是就可以了?也许有点用,但是问题在于,这还是不可预测、不能保证的。所以本质上还是不能指望。实践中,由于finalize拖慢垃圾收集,导致大量对象堆积,也是一种典型的导致OutOfMemeryError的原因。

从另一个角度,我们要确保回收资源就是因为资源是有限的,垃圾收集时间的不可预测,可能会极大加剧资源占用。这意味着对于消耗非常高频的资源,千万不要指望finalize去承担资源释放的主要职责,最多让finalize作为最后的“守门员”,况且它已经暴露了如此多的问题。这也是为什么推荐,资源用完即显式释放,或者利用资源池来尽量重用

finalize还有一个负作用,就是当在进行资源回收的时候,如果出错似乎除了生吞异常,没有什么好办法。也就是说,你很可能得不到关于此时发生错误的任何有效信息。

既然如此不堪,有什么机制可以替换finalize吗?

Java平台从Java 9开始正在逐步使用java.lang.ref.Cleaner来替换掉原有的finalize实现。Cleaner的实现利用了幻象引用(PhantomReference),这是一种常见的所谓post-mortem清理机制。

猜你喜欢

转载自blog.csdn.net/qweqwruio/article/details/81330196
今日推荐