2

据我了解 finalize() 和 GC 是两个不同的方面。GC 使用 finalize() 方法来释放对象内存。我们无法说明 GC 何时发生(即使我们显式调用 System.gc())。但是我们可以显式调用一个对象的 finalize()。

Will the function be executed immediately(memory freed) or it waits till GC
occurs like System.gc() call?

此外,根据文档,Java 虚拟机不会为任何给定对象多次调用 finalize 方法。

那么当我们首先调用 finalize() 并且 GC 在稍后的时间点发生时会发生什么。

If object memory is not freed on explicit call to object.finalize() then would't 
it being called again in the GC process violate the calling only once rule? 
4

3 回答 3

7

你完全错了。

简短的回答: finalize()是一种在对象准备好进行垃圾回收之前清理资源(例如打开的文件)的方法(当没有对象对其具有强引用时)。它可能/不会被调用。它比内存释放提前了一步。

长答案:

有一个单独的守护线程称为终结器线程,负责调用 finalize() 方法。终结队列是放置准备调用 finalize() 方法的对象的队列。

  1. 创建对象时,JVM 会检查用户是否覆盖了 finalize() 方法。如果有,那么它在内部说明这个特定对象有 finalize() 方法。

当一个对象准备好进行垃圾收集时,垃圾收集器线程检查该特定对象是否具有来自 (1) 中提到的表的 finalize()。

  • 2a)如果没有,则将其发送以进行垃圾收集。

    2b) 它是有的,然后它被添加到终结队列中。它从表 (1) 中删除对象的条目。

终结器线程不断轮询队列。对于队列中的每个对象,都会调用其 finalize() 方法。在从 (2) 调用 finalize() 循环后,再次重复。如果此对象仍然没有强引用,则发送 GC。如果有,则调用 ALWAYS (2a),因为该条目在 (2b) 中被删除

Basically finalize() method is only called once.

那么上述循环有什么问题呢?

从(1)。它需要额外的时间来创建对象。Java 中的内存分配比 malloc/calloc 等快 5 到 10 倍。在记录表中的对象等过程中获得的所有时间都丢失了。我曾经尝试过。在循环中创建 100000 个对象,并在 2 种情况下测量程序终止所用的时间:一种没有 finalize(),第二种有 finalize()。发现它快了 20%。

来自 (2b):内存泄漏和饥饿。如果队列中的对象引用了大量内存资源,那么除非该对象准备好进行 GC,否则所有这些对象都不会被释放。如果所有对象都是重量级对象,则可能会出现短缺。

来自 (2b):因为 finalize() 只被调用一次,如果在 finalize() 中你有一个对“this”对象的强引用怎么办。下次对象的 finalie() 永远不会被调用,因此可能会使对象处于不一致的状态。

如果在 finalize() 中抛出异常,则将其忽略。

您不知道何时调用 finalize(),因为您无法控制何时调用 GC。有时可能会发生您在 finalize() 中打印值但从未显示输出的情况,因为您的程序可能在调用 finalize() 时已经终止。

因此避免使用它。而是创建一个方法说 dispose() 它将关闭必要的资源或用于最终日志等。

于 2013-08-29T12:11:30.727 回答
1

根据文档:

对于任何给定的对象,Java 虚拟机永远不会多次调用 finalize 方法。

但是,您不能强制 GC 运行,您可以通过System.gc(). finalize()因此,最好的方法是在覆盖时将释放资源的代码放入方法中。

于 2013-08-29T12:12:02.373 回答
1

答案在 Object.finalize API

1) GC 调用 finalize() 所以 finalize() 和 GC 不是两个不同的方面

2)你不应该手动调用finalize,但如果你这样做不会释放任何内存,也不会影响GC行为

3)据说保证GC不会调用finalize两次,我们的调用不算

于 2013-08-29T12:15:40.640 回答