Java 中终结的目的是什么?
我对终结的理解是这样的:
为了清理或回收对象占用的内存,垃圾收集器开始起作用。 (自动调用?)
然后垃圾收集器取消引用该对象。有时,垃圾收集器无法访问该对象。然后调用 Finalize 进行最终的清理处理,之后可以调用垃圾收集器。
这是对最终确定的准确描述吗?
My understanding of finalization is this:
To clean up or reclaim the memory that an object occupies, the Garbage collector comes into action. (automatically is invoked?)
The garbage collector then dereferences the object. Sometimes, there is no way for the garbage collector to access the object. Then finalize is invoked to do a final clean up processing after which the garbage collector can be invoked.
Is this an accurate description of finalization?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
垃圾收集器在后台自动工作(虽然可以显式调用它,但这种需要应该很少)。它基本上只清理未被其他对象引用的对象(当然,整体情况更复杂,但这是基本思想)。因此它不会更改任何活动对象中的任何引用。如果无法从任何活动对象访问某个对象,则意味着可以安全地对其进行垃圾回收。
终结意味着清理对象获取的资源(不是内存,而是其他资源,例如文件句柄、端口、数据库连接等)。然而,它并没有真正解决:-(
finalize()
是不可预测的finalize()
会被调用因此,即使保证会调用它,它也不是释放资源的好地方:当调用它来释放您打开的所有数据库连接时,系统可能已经完全耗尽了可用连接,并且您的应用程序不再工作。
The garbage collector is working automatically in the background (although it can be explicitly invoked, but the need for this should be rare). It basically cleans up only objects which are not referenced by other objects (granted, the full picture is more complicated, but this is the basic idea). So it does not change any references in any live objects. If an object can not be accessed from any live object, this means that it can be safely garbage collected.
Finalization was meant to clean up resources acquired by the object (not memory, but other resources, e.g. file handles, ports, DB connections etc.). However, it did not really work out :-(
finalize()
will be calledfinalize()
will be called ever!So even if it were guaranteed to be called, it would not be a good place to release resources: by the time it is called to free up all the DB connections you have opened, the system may have run out of free connections completely, and your app does not work anymore.
来自这篇文章:
另外,Sun 的这篇文章有一些很好的图表解释了该过程。
From this article:
Also, this article from Sun has some nice diagrams explaining the process.
没有。仅当垃圾收集器尝试回收您的对象时,才会运行
finalize()
方法。您的对象使用的任何内存都会(通常,我想不出例外)自动连接到您的对象并随之清理。因此,终结并不意味着释放内存,而是释放与您的对象可能关联的任何其他资源。例如,这可以用于关闭打开的文件或数据库连接,或者可能运行一些与操作系统交互的低级代码以释放一些系统级资源。
Nope. The
finalize()
method is run only if the garbage collector attempts to reclaim your object.Any memory used by your object will (usually, I can't think of an exception) automatically be connected to your object and cleaned up along with it. Finalization, therefore, isn't meant for freeing memory, but rather any other resources your object may be associated with. For example, this could be used to close open files or database connections, or perhaps run some low-level code interfacing with the operating system to release some system-level resources.
实际上,这是finalize()方法的行为:
一旦垃圾收集器运行(虚拟机决定它需要释放内存,你不能强制它运行)并决定从这个对象收集内存(这意味着没有至少从可到达的对象中不再指向它的引用),就在删除它占用的内存之前,它在该对象上运行方法finalize()。您可以确定,如果垃圾收集,该对象将在消失之前运行 Finalize(),但您无法确定它是否会被 GC 处理,因此您根本不应该依赖该方法来进行任何清理。您应该在finally{}块内运行清理语句,而不是使用finalize(),因为它不能保证运行。
此外,有些人做了性能测试,结果表明 Finalize 方法会在一定程度上减慢对象的创建/销毁速度。我不记得来源,因此将此信息视为不太可靠。 :)
Actually, here's the behavior of the finalize() method:
Once the Garbage collector runs (the VM decides it needs to free up memory, you cannot force it to run) and decided to collect the memory from this object (which means there are NO references pointing to it anymore, from reachable objects at least), just before it deletes the memory occupied by it, it runs the method finalize() on the object. You can be sure that if garbage collected, the object will run finalize() just before it disappears, but you cannot be sure that it will get GC'ed at all so you shouldn't rely on the method to do any sanitizing at all. You should run sanitizing statements inside finally {} blocks and not use finalize() as it is not guaranteed to run.
Furthermore, some people have done performance tests and showed that the finalize method somewhat slows down creation/destruction of the object. I cannot remember the source so treat this info as not very reliable. :)
最终化用于清理垃圾收集器无法释放的资源。例如,考虑一个直接从操作系统分配(通过某些
本机
API)资源的程序。这通常会产生某种“句柄”(UNIX 文件描述符或 Windows HANDLE,或类似的东西):那么,如果您的代码分配类
Wrapper
的实例,会发生什么?该类分配某种特定于操作系统的资源,并在成员变量中保留对其(句柄)的引用。但是,当对包装器实例的最后一个 Java 引用丢失时会发生什么?现在,垃圾收集器将(在某些时候)回收现已失效的包装器实例的空间。但是包装器分配的操作系统资源会发生什么情况呢?如果它是昂贵的资源,例如文件描述符,那么在上述场景中它会被泄漏,这是一件坏事。为了让您的代码在这种情况下得到清理,需要使用
finalize
方法。现在,当 GC 回收包装器实例的空间时,终结器会确保资源正确返回到操作系统。
这听起来不错,但正如其他人已经指出的那样,缺点是,终结本质上是不可靠的:您不知道终结器何时运行。更糟糕的是:根本无法保证它会运行。因此,最好提供一个
dispose
机制,并仅将终结用作安全网,以防类的客户端忘记正确处置其引用:Finalization is used to clean up resources, which cannot be freed by the garbage collector. For example, consider a program which allocates (via some
native
API) resources directly from the OS. This usually yields some kind of "handle" (a UNIX file descriptor or Windows HANDLE, or something similar):So, what happens, if your code allocates an instance of class
Wrapper
? Well the class allocates some kind of OS specific resource and keeps a reference to it (the handle) in a member variable. But what happens, when the last Java reference to a wrapper instance is lost? Now, the garbage collector will (at some point) reclaim the space of the now defunct wrapper instance. But what happens to the OS resource allocated by the wrapper? It will be leaked in the above scenario, which is a bad thing, if it is a costly resource, such as a file descriptor.In order to allow your code to clean up in such a scenario, there is the
finalize
method.Now, when the GC reclaims the space of a wrapper instance, the finalizer makes sure, that the resource is properly returned to the OS.
This sounds all nice, but as others have already pointed out, the downside is, that finalization is inherently unreliable: you do not know when the finalizer will be run. Worse: there are no guarantees that it will be run at all. So ist best to provide an
dispose
mechanism and use finalization only as safety-net in case, the clients of your class forget to properly dispose their references: