Java面试问题:finalize()方法

30
在面试中我被问到以下问题:

在对象被垃圾回收之前,调用对象的finalize()方法是发生的最后一件事情。

我选择了 True 但是答案是错误的。您可以解释一下为什么吗?
回答:False。
finalize() 方法不保证会被调用。例如,在JVM退出时,它们通常不会被调用。此外,由于可达性分析算法和其他优化,不清楚何时将对象标记为垃圾,因此 finalize() 方法可能永远不会被调用。

请阅读此文章: http://www.codeguru.com/java/tij/tij0051.shtml - Damian Leszczyński - Vash
@Vash,那篇文章已经非常过时了。 - finnw
6个回答

59

2
确认。收集不是对象生命周期的最终状态,它是释放。感谢链接并学到了新知识 :) - Andreas Dolk
非常感谢这个。非常有用的知识。 - Cambium
问题在于,“collected”是一个口语化的术语,其解释因人而异。有些人使用“collected”来指代垃圾收集器确定对象不可达的事件,而其他人则使用同样的词汇来表示对象的内存已被回收。根据这种主观意义,答案也会不同。在规范中,并不存在“collected”状态。 - Holger

8
我认为这暗示着在GC真正丢弃对象之前,实际上可以对对象进行其他操作/发生其他事情。
引用参考文献:
[...] finalize方法可以采取任何行动,包括使此对象再次可用于其他线程;然而,finalize的通常目的是在对象被不可撤销地丢弃之前执行清理操作。例如,表示输入/输出连接的对象的finalize方法可能执行显式I/O事务以断开连接,在对象被永久丢弃之前执行清理操作。
因此,在这种情况下,finalizing过程并不是GC丢弃对象之前的最后一件事。

2

不能保证finalize()方法总是会被调用,甚至垃圾回收都不一定会运行。

假设程序结束(通过调用System.exit()或所有运行的线程都结束),那么JVM将直接退出,它不会清理所有东西并调用所有对象的finalize()方法。

因此,在finalize()方法中放置绝对必须运行的清理任务并不是一个好主意。


8
这并没有回答这个问题。 - unbeli
它部分回答了这个问题,并提供了一些有用的信息,解释了为什么finalize()并不像许多程序员认为的那样有用。 - Jesper
喷洒有用的琐事固然不错,但坚持主题更好。 - unbeli
感谢您的回答。即使它不是一个确切的答案,这也是一条有趣的知识小常识。 - Andrei Ciobanu

2

我猜你可以为两个答案进行辩护,finalize()方法是在垃圾回收器在收集对象之前调用的,但在应用程序结束之前不能确定是否会发生这种情况。并不是所有有资格进行垃圾回收的对象都必须被回收。您可能永远无法依赖于任何对象来调用finalize()方法。


1

顺序是错误的,就像DR已经展示的那样。

当垃圾回收器识别到对象不可达时,对象会将其状态更改为collected

那么在检测到这种“不可达”条件之前,应该采取行动来完成对象的最终化呢?实际上,如果对象的finalize方法被覆盖,垃圾回收器会标记已收集的对象进行最终化。我们真的不想对仍然可达(例如“正在使用中”)的对象进行最终化。

无论如何,这是一个很好的问题,因为你倾向于说“是的,这是真的”。


0

您可以在finalize方法中通过使某些东西指向它来复活对象,以便在调用finalize方法后对象不会被GC收集。但是当对象再次可用于垃圾回收时,由于已被标记/标记为已完成,因此不会调用该对象的finalize方法。因此,在GC之前可能会发生调用finalize方法或对象复活的情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接