据我所知,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?
答案 0 :(得分:6)
你完全错了。
简短回答:
finalize()
是在对象准备好进行垃圾收集之前清理资源(例如打开文件)的一种方法(当没有对象具有强引用时)。它可能/不会被调用。它比内存释放领先一步。
答案很长:
有一个单独的守护程序线程,称为终结器线程,负责调用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,否则所有这些对象都不会被释放。如果所有对象都是重量级对象,那么可能会出现短缺。
From(2b):因为finalize()只被调用一次,所以如果在finalize()中你有一个强烈的“this”对象引用。下次永远不会调用对象的finalie()因此会使对象处于不一致状态。
如果在finalize()内部抛出异常,则忽略它。
您不知道何时调用finalize(),因为您无法控制何时调用GC。有时可能会在finalize()中打印值,但输出永远不会显示,因为你的程序可能在调用finalize()时被终止。
因此避免使用它。而是创建一个方法,例如dispose(),它将关闭必需资源或最终日志等。
答案 1 :(得分:1)
任何给定对象的Java虚拟机都不会多次调用finalize方法。
但是,您无法强制GC运行,您只需通过System.gc()
进行询问即可。因此,最佳方法是在覆盖时将资源释放代码放入finalize()
方法。
答案 2 :(得分:1)
答案在Object.finalize API中
1)GC调用finalize(),因此finalize()和GC不是两个不同的方面
2)你不应该手动调用finalize,但如果你这样做就不会释放任何内存,也不会影响GC行为
3)据说保证GC不会两次调用finalize,我们的调用不计算