Java中的finalize()方法什么时候被调用?
我需要知道 何时Finalize()
方法在 JVM
中调用。我创建了一个测试类,当通过覆盖调用 finalize()
方法时,该测试类会写入文件。它没有被执行。谁能告诉我它不执行的原因吗?
I need to know when the finalize()
method is called in the JVM
. I created a test class which writes into a file when the finalize()
method is called by overriding it. It is not executed. Can anybody tell me the reason why it is not executing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(18)
当对象即将被垃圾回收时,将调用
finalize
方法。这可以是在它有资格进行垃圾收集之后的任何时间。请注意,对象完全有可能永远不会被垃圾回收(因此永远不会调用
finalize
)。当对象永远不符合 gc 条件时(因为它在 JVM 的整个生命周期中都是可访问的),或者在对象变得符合条件的时间和 JVM 停止运行的时间之间实际上没有运行垃圾收集时,就会发生这种情况(这种情况通常发生在简单的情况下)测试程序)。有多种方法可以告诉 JVM 在尚未调用的对象上运行 Finalize,但使用它们也不是一个好主意(该方法的保证也不是很强) )。
如果您依靠
finalize
来使应用程序正确运行,那么您就做错了。finalize
应该仅用于清理(通常是非Java)资源。正是如此,因为 JVM 不保证在任何对象上调用 Finalize。The
finalize
method is called when an object is about to get garbage collected. That can be at any time after it has become eligible for garbage collection.Note that it's entirely possible that an object never gets garbage collected (and thus
finalize
is never called). This can happen when the object never becomes eligible for gc (because it's reachable through the entire lifetime of the JVM) or when no garbage collection actually runs between the time the object become eligible and the time the JVM stops running (this often occurs with simple test programs).There are ways to tell the JVM to run
finalize
on objects that it wasn't called on yet, but using them isn't a good idea either (the guarantees of that method aren't very strong either).If you rely on
finalize
for the correct operation of your application, then you're doing something wrong.finalize
should only be used for cleanup of (usually non-Java) resources. And that's exactly because the JVM doesn't guarantee thatfinalize
is ever called on any object.一般来说,最好不要依赖
finalize()
进行任何清理等。根据 Javadoc (值得一读),它是:
正如 Joachim 指出的,如果对象始终可访问,那么在程序的生命周期中这可能永远不会发生。
此外,不保证垃圾收集器在任何特定时间运行。一般来说,我想说的是
finalize()
可能不是一般情况下使用的最佳方法,除非有特定的需要它。In general it's best not to rely on
finalize()
to do any cleaning up etc.According to the Javadoc (which it would be worth reading), it is:
As Joachim pointed out, this may never happen in the life of a program if the object is always accessible.
Also, the garbage collector is not guaranteed to run at any specific time. In general, what I'm trying to say is
finalize()
is probably not the best method to use in general unless there's something specific you need it for.finalize()
永远不会在引用自以下内容的 :http://www.janeg.ca/scjp/gc/finalize.html您还可以查看这篇文章:
quoted from: http://www.janeg.ca/scjp/gc/finalize.html
You could also check this article:
Java
finalize()
方法不是析构函数,不应该用于处理应用程序所依赖的逻辑。 Java 规范规定,不保证在应用程序的生命周期内调用 Finalize 方法。您可能想要的是
finally
和清理方法的组合,如下所示:这将正确处理
MyClass()
构造函数抛出异常时的情况。The Java
finalize()
method is not a destructor and should not be used to handle logic that your application depends on. The Java spec states there is no guarantee that thefinalize
method is called at all during the livetime of the application.What you problably want is a combination of
finally
and a cleanup method, as in:This will correctly handle the situation when the
MyClass()
constructor throws an exception.查看《Effective Java》第二版第 27 页。
第 7 项:避免终结器
要终止资源,请使用 try-finally 代替:
Check out Effective Java, 2nd edition page 27.
Item 7: Avoid finalizers
To terminate a resource, use try-finally instead:
Finalize方法将在GC检测到对象不再可达之后、实际回收对象使用的内存之前被调用。
如果一个对象永远不会变得无法访问,则永远不会对其调用
finalize()
。如果 GC 不运行,则可能永远不会调用
finalize()
。 (通常,GC 仅在 JVM 认为可能有足够的垃圾值得执行时才运行。)在 GC 确定某个特定对象无法访问之前,可能需要多个 GC 周期。 (Java GC 通常是“分代”收集器...)
一旦 GC 检测到某个对象无法访问且可终结,它就会被放入终结队列中。终结通常与普通 GC 异步发生。
(JVM 规范实际上允许 JVM 从不运行终结器...前提是它不回收对象使用的空间。以这种方式实现会被削弱/无用,但如果这种行为是“允许的”。)
结果是依赖最终确定来完成必须在确定的时间范围内完成的事情是不明智的。根本不使用它们是“最佳实践”。应该有一种更好(即更可靠)的方法来完成您在 Finalize() 方法中尝试执行的任何操作。
终结的唯一合法用途是清理与应用程序代码丢失的对象关联的资源。即使如此,您也应该尝试编写应用程序代码,以便一开始就不会丢失对象。 (例如,使用 Java 7+ try-with-resources 确保始终调用
close()
...)这很难说,但有几种可能性:
The finalize method will be called after the GC detects that the object is no longer reachable, and before it actually reclaims the memory used by the object.
If an object never becomes unreachable,
finalize()
will never be called on it.If the GC doesn't run then
finalize()
may never be called. (Normally, the GC only runs when the JVM decides that there is likely to enough garbage to make it worthwhile.)It may take more than one GC cycle before the GC determines that a specific object is unreachable. (Java GCs are typically "generational" collectors ...)
Once the GC detects an object is unreachable and finalizable, it is places on a finalization queue. Finalization typically occurs asynchronously with the normal GC.
(The JVM spec actually allows a JVM to never run finalizers ... provided that it doesn't reclaim the space used by the objects. A JVM that was implemented this way would be crippled / useless, but it this behavior is "allowed".)
The upshot is that it is unwise to rely on finalization to do things that have to be done in a definite time-frame. It is "best practice" not to use them at all. There should be a better (i.e. more reliable) way to do whatever it is you are trying to do in the
finalize()
method.The only legitimate use for finalization is to clean up resources associated with objects that have been lost by application code. Even then, you should try to write the application code so that it doesn't lose the objects in the first place. (For example, use Java 7+ try-with-resources to ensure that
close()
is always called ...)It is hard to say, but there are a few possibilities:
由于 JVM 调用 Finalize() 方法存在不确定性(不确定被重写的 Finalize() 是否会被执行),出于研究目的,观察调用 Finalize() 时发生的情况的更好方法是通过命令 System.gc() 强制 JVM 调用垃圾回收。
具体来说,当对象不再使用时调用 Finalize()。但是当我们尝试通过创建新对象来调用它时,它的调用并不确定。因此,为了确定性,我们创建了一个
null
对象c
,它显然没有未来的用途,因此我们看到了对象c
的 Finalize 调用。示例
输出
注意 - 即使在打印了 70 个之后并且此后对象 b 不再在程序中使用,也不确定 b 是否被清除或不由 JVM 执行,因为不会打印“Called Finalize method in class Bike...”。
Since there is an uncertainity in calling of finalize() method by JVM (not sure whether finalize() which is overridden would be executed or not), for study purposes the better way to observe what happens when finalize() is called, is to force the JVM to call garbage collection by command
System.gc()
.Specifically, finalize() is called when an object is no longer in use. But when we try to call it by creating new objects there is no certainty of its call. So for certainty we create a
null
objectc
which obviously has no future use, hence we see the objectc
's finalize call.Example
Output
Note - Even after printing upto 70 and after which object b is not being used in the program, there is uncertainty that b is cleared or not by JVM since "Called finalize method in class Bike..." is not printed.
Finalize 将打印出类创建的计数。
如
你所见。以下输出显示当类计数为 36 时第一次执行 gc。
finalize will print out the count for class creation.
main
As you can see. The following out put show the gc got executed first time when the class count is 36.
最近在与终结器方法进行斗争(为了在测试期间处理连接池),我不得不说终结器缺少很多东西。使用 VisualVM 观察并使用弱引用跟踪实际交互,我发现在 Java 8 环境(Oracle JDK、Ubuntu 15)中存在以下情况:
最终想法
Finalize 方法不可靠,但只能用于一件事。您可以确保对象在垃圾收集之前已关闭或处置,从而如果正确处理涉及生命周期结束操作的更复杂生命周期的对象,则可以实现故障安全。这是我能想到的一个值得超越它的原因。
Having wrestled with finalizer methods lately (in order to dispose connection pools during testing), I have to say that finalizer lacks many things. Using VisualVM to observe as well as using weak references to track the actual interaction I found that following things are true in a Java 8 environment (Oracle JDK, Ubuntu 15):
Final Thought
Finalize method is unreliable but can be used for one thing only. You can ensure that an object was closed or disposed before it was garbage collected making it possible to implement a fail safe if objects with a more complex life-cylce involving a end-of-life action are handled correctly. That is the one reason I can think of that makes it worth in order to override it.
如果一个对象无法从任何活动线程或任何静态引用访问,那么它就符合垃圾收集或 GC 的条件,换句话说,如果一个对象的所有引用都为空,那么您可以说该对象有资格进行垃圾收集。循环依赖不计为引用,因此如果对象 A 具有对象 B 的引用,并且对象 B 具有对象 A 的引用,并且它们没有任何其他实时引用,则对象 A 和 B 都将有资格进行垃圾收集。
通常,在以下情况下,对象在 Java 中适合垃圾回收:
An Object becomes eligible for Garbage collection or GC if its not reachable from any live threads or any static refrences in other words you can say that an object becomes eligible for garbage collection if its all references are null. Cyclic dependencies are not counted as reference so if Object A has reference of object B and object B has reference of Object A and they don't have any other live reference then both Objects A and B will be eligible for Garbage collection.
Generally an object becomes eligible for garbage collection in Java on following cases:
finalize 方法不受保证。当对象符合 GC 条件时,将调用此方法。在许多情况下,对象可能不会被垃圾收集。
finalize method is not guaranteed.This method is called when the object becomes eligible for GC. There are many situations where the objects may not be garbage collected.
有时,当一个对象被破坏时,它必须做出一个动作。例如,如果一个对象具有文件句柄或字体等非 java 资源,则可以在销毁对象之前验证这些资源是否已释放。为了管理这种情况,java 提供了一种称为“finalizing”的机制。通过完成它,您可以定义当对象即将从垃圾收集器中删除时发生的特定操作。
要将终结器添加到类中,只需定义 finalize() 方法即可。 Java 执行时每当要删除该类的对象时都会调用此方法。在 Finalize 方法()中,您可以指定在销毁对象之前要执行的操作。
垃圾收集器会定期搜索不再引用任何运行状态的对象或间接搜索任何其他具有引用的对象。在释放资产之前,Java 运行时会调用对象的 Finalize() 方法。 finalize() 方法具有以下一般形式:
使用 protected 关键字,可以防止类外部的代码访问 finalize()。
重要的是要理解 finalize() 在垃圾回收之前被调用。例如,当对象离开作用域时,不会调用它。这意味着您无法知道 Finalize() 何时或是否会被执行。因此,程序必须提供其他方法来释放系统资源或对象使用的其他资源。 您不应该依赖finalize()来保证程序的正常运行。
Sometimes when it is destroyed, an object must make an action. For example, if an object has a non-java resource such as a file handle or a font, you can verify that these resources are released before destroying an object. To manage such situations, java offers a mechanism called "finalizing". By finalizing it, you can define specific actions that occur when an object is about to be removed from the garbage collector.
To add a finalizer to a class simply define the finalize() method. Java execution time calls this method whenever it is about to delete an object of that class. Within the finalize method() you specify actions to be performed before destroying an object.
The garbage collector is periodically searched for objects that no longer refer to any running state or indirectly any other object with reference. Before an asset is released, the Java runtime calls the finalize() method on the object. The finalize() method has the following general form:
With the protected keyword, access to finalize() by code outside its class is prevented.
It is important to understand that finalize() is called just just before the garbage collection. It is not called when an object leaves the scope, for example. It means you can not know when, or if, finalize() will be executed. As a result, the program must provide other means to free system resources or other resources used by the object. You should not rely on finalize() for normal running of the program.
JDK 18 的最新消息
根据 JEPS 421 在 openjdk 18 上交付了最终版本,因此提供了以下功能:
finalize()
方法将被标记为deprecated(forRemoval=true)
,这意味着在 jdk 18 之后的某个更高版本中将永久删除。从 jdk 18 开始,一个新命令 -行选项
--finalization=disabled
禁用所有地方的终结机制,即使对于 jdk 本身内部的声明也是如此。这也与这里的问题相关,因为计划删除它的原因是它包含一些主要缺陷。这些缺陷之一是,从对象变得无法访问到调用其终结器之间可能需要很长的时间。 GC 确实不保证任何终结器都会被调用。
Recent news from JDK 18
According to JEPS 421 delivered on openjdk 18 the finalization and therefore the functionality of
finalize()
method will be marked asdeprecated(forRemoval=true)
meaning the permanent removal would follow in some later version after jdk 18.As from jdk 18 a new command-line option
--finalization=disabled
disables finalization mechanism everywhere even for declarations inside the jdk itself.This is also relevant to this question here as the reason it is planned for removal, is some major flaws it contains. One of those flaws is that a very long time may pass between the moment an object becomes unreachable and the moment its finalizer is called. It is also true that the GC provides no guarantee that any finalizer will ever be called.
我们重写finalize方法的类
finalize方法被调用的机会,
当内存因转储对象而超载时,
gc将调用finalize方法,运行并查看控制台,当内存超载时,您不会发现finalize方法被频繁调用然后finalize方法将被调用。
Class where we override finalize method
The chances of finalize method being called
when the memory is overloaded with dump objects the gc will call finalize method
run and see the console, where you dont find the finalize method being called frequently, when the memory is getting overloaded then the finalize method will be called.
finalize()
在垃圾回收之前调用。当对象超出范围时不会调用它。这意味着您无法知道finalize()
何时或是否会被执行。示例:
如果您的程序在垃圾收集器发生之前结束,则
finalize()
将不会执行。因此,它应该用作备份过程,以确保正确处理其他资源,或用于特殊用途的应用程序,而不是作为程序在正常操作中使用的手段。finalize()
is called just before garbage collection. It is not called when an object goes out of scope. This means that you cannot know when or even iffinalize()
will be executed.Example:
If your program end before garbage collector occur, then
finalize()
will not execute. Therefore, it should be used as backup procedure to ensure the proper handling of other resources, or for special use applications, not as the means that your program uses in its normal operation.来源
Source
正如 https:/ 中指出的/wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers,
As pointed out in https://wiki.sei.cmu.edu/confluence/display/java/MET12-J.+Do+not+use+finalizers,
尝试运行该程序以更好地理解
Try runiing this Program for better understanding