当我们显式调用 finalize() 时,对象内存是不是被释放? [复制]

Posted

技术标签:

【中文标题】当我们显式调用 finalize() 时,对象内存是不是被释放? [复制]【英文标题】:Is Object memory freed when we explicitly call finalize() on it? [duplicate]当我们显式调用 finalize() 时,对象内存是否被释放? [复制] 【发布时间】:2013-09-01 20:46:16 【问题描述】:

据我了解,finalize() 和 GC 是两个不同的方面。 GC 使用 finalize() 方法来释放对象内存。我们无法说明 GC 何时发生(即使我们显式调用 System.gc())。但我们可以显式调用 Object 的 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? 

【问题讨论】:

@duffymo 不是真的... 【参考方案1】:

你完全错了。

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

长答案:

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

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

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

2a) 如果没有,则将其发送给垃圾回收。

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

终结器线程不断轮询队列。对于队列中的每个对象,都会调用其 finalize() 方法。在从 (2) 调用 finalize() 循环后,再次重复。如果此对象仍然没有强引用,则发送 GC。如果 然后总是调用 (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() 它将关闭必要的资源或用于最终日志等。

【讨论】:

所以我们不能在任何对象上显式调用 finalize(),即使我们这样做,它也只会在 GC 发生时执行。对吗? 如果您想打电话,请随时致电。但这根本不可取。如果你调用它,它将像任何其他方法调用一样执行。 GC 调用稍后会出现(尽管它可能会出现也可能不会出现)。阅读上文了解更多信息 @Jatin - +1(尤其是第一句话),但请查看我的编辑。你描述了 what finalize() 做了什么,我描述了 why 有人可能认为他们需要它。 语句'JVM检查对象是否有finalize()方法'是什么意思?所有对象都有 finalize() 方法,因为所有扩展 Object 类? 规范有一个“平凡”终结器的概念,即 a) java.lang.Object 声明的 finalize() 方法,b) 空的 finalize() 方法,或 c) finalize() 方法由对另一个简单的 finalize 方法的唯一 super.finalize() 调用组成。所以当一个对象被创建时,JVM会检查它的类是否有一个“不平凡”的finalize方法。【参考方案2】:

As per docs:

Java 虚拟机不会为任何给定对象多次调用 finalize 方法。

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

【讨论】:

仍然取决于 jvm 但这基本上就是答案【参考方案3】:

答案在 Object.finalize API 中

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

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

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

【讨论】:

以上是关于当我们显式调用 finalize() 时,对象内存是不是被释放? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

java 怎么对一个对象强制垃圾回收

java有自动垃圾回收机制

finalize()用途何在?

Java核心技术1

9.垃圾回收机制和JVM

tij学习笔记Java finalize()的使用