Java中终结的目的是什么?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2450580/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 07:51:25  来源:igfitidea点击:

What is the purpose of finalization in Java?

javafinalization

提问by

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.

垃圾收集器然后取消引用该对象。有时,垃圾收集器无法访问对象。然后调用 finalize 进行最后的清理处理,之后可以调用垃圾收集器。

Is this an accurate description of finalization?

这是对最终确定的准确描述吗?

采纳答案by Péter T?r?k

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 wasmeant 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 :-(

最终确定旨在清理由对象(而不是存储,而是其他资源,如文件句柄,港口,DB连接等)获得的资源。然而,它并没有真正奏效:-(

  • it is unpredictable when finalize()will be called
  • in fact, there is no guarantee that finalize()will be called ever!
  • 无法预测何时finalize()会被调用
  • 事实上,不能保证finalize()会被调用!

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.

所以即使保证被调用,它也不是释放资源的好地方:当它被调用以释放你打开的所有数据库连接时,系统可能已经完全耗尽了空闲连接,并且你的应用程序不再工作了。

回答by Carl Smotricz

Nope. The finalize()method is run only if the garbage collector attempts to reclaim your object.

不。该finalize()方法仅在垃圾收集器尝试回收您的对象时运行。

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.

您的对象使用的任何内存都将(通常,我想不出例外)自动连接到您的对象并与它一起清理。因此,终结并不意味着释放内存,而是释放对象可能与之关联的任何其他资源。例如,这可用于关闭打开的文件或数据库连接,或者运行一些与操作系统交互的低级代码以释放一些系统级资源。

回答by danben

From this article:

这篇文章

Any instances of classes that implement the finalize() method are often called finalizable objects. They will not be immediately reclaimed by the Java garbage collector when they are no longer referenced. Instead, the Java garbage collector appends the objects to a special queue for the finalization process. Usually it's performed by a special thread called a "Reference Handler" on some Java Virtual Machines. During this finalization process, the "Finalizer" thread will execute each finalize() method of the objects. Only after successful completion of the finalize() method will an object be handed over for Java garbage collection to get its space reclaimed by "future" garbage collection.

You are free to do virtually anything in the finalize() method of your class. When you do that, please do not expect the memory space occupied by each and every object to be reclaimed by the Java garbage collector when the object is no longer referenced or no longer needed. Why? It is not guaranteed that the finalize() method will complete the execution in timely manner. Worst case, it may not be even invoked even when there are no more references to the object. That means it's not guaranteed that any objects that have a finalize() method are garbage collected.

实现 finalize() 方法的类的任何实例通常称为可终结对象。当它们不再被引用时,Java 垃圾收集器不会立即回收它们。取而代之的是,Java 垃圾收集器将对象附加到一个特殊的队列中,以供终结过程使用。通常它由一些 Java 虚拟机上称为“引用处理程序”的特殊线程执行。在这个终结过程中,“Finalizer”线程将执行对象的每个 finalize() 方法。只有在 finalize() 方法成功完成后,才会将对象移交给 Java 垃圾收集,以便“未来”垃圾收集回收其空间。

你几乎可以在你的类的 finalize() 方法中做任何事情。当您这样做时,请不要期望每个对象占用的内存空间在不再引用或不再需要对象时被 Java 垃圾收集器回收。为什么?不保证 finalize() 方法会及时完成执行。最坏的情况是,即使没有更多对对象的引用,它也可能不会被调用。这意味着不能保证任何具有 finalize() 方法的对象都被垃圾收集。

Also, this articlefrom Sun has some nice diagrams explaining the process.

此外,Sun 的这篇文章有一些很好的图表来解释这个过程。

回答by pnt

Actually, here's the behavior of the finalize() method:

实际上,这是 finalize() 方法的行为:

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.

一旦垃圾收集器运行(VM 决定它需要释放内存,你不能强迫它运行)并决定从此对象收集内存(这意味着不再有指向它的引用,至少从可达对象) ,就在它删除它所占用的内存之前,它会在对象上运行 finalize() 方法。您可以确定,如果垃圾被收集,该对象将在它消失之前运行 finalize(),但您无法确定它是否会被 GC 处理,因此您根本不应该依赖该方法进行任何清理. 您应该在 finally {} 块内运行清理语句,而不是使用 finalize() 因为它不能保证运行。

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. :)

此外,有些人进行了性能测试,并表明 finalize 方法在某种程度上减慢了对象的创建/销毁速度。我不记得来源,因此将此信息视为不太可靠。:)

回答by Dirk

Finalization is used to clean up resources, which cannot be freed by the garbage collector. For example, consider a program which allocates (via some nativeAPI) resources directly from the OS. This usually yields some kind of "handle" (a UNIX file descriptor or Windows HANDLE, or something similar):

终结用于清理垃圾收集器无法释放的资源。例如,考虑一个native直接从操作系统分配(通过一些API)资源的程序。这通常会产生某种“句柄”(UNIX 文件描述符或 Windows 句柄,或类似的东西):

class Wrapper {
    private long handle;

    private Handle(long h) {
        handle = h;
    }

    private static native long getHandleFromOS();

    static Wrapper allocate() {
        return new Handle(getHandleFromOS());
    }
}

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.

那么,如果您的代码分配了一个 class 实例,会发生什么Wrapper?好吧,该类分配了某种特定于操作系统的资源,并在成员变量中保留对它的引用(句柄)。但是,当最后一个对包装器实例的 Java 引用丢失时会发生什么?现在,垃圾收集器将(在某个时候)回收现已失效的包装器实例的空间。但是包装器分配的操作系统资源会发生什么?在上面的场景中会被泄露,这是一件坏事,如果它是一个昂贵的资源,比如一个文件描述符。

In order to allow your code to clean up in such a scenario, there is the finalizemethod.

为了让您的代码在这种情况下清理,有finalize方法。

class Wrapper {
    private long handle;

    private Handle(long h) {
        handle = h;
    }

    protected void finalize() {
        returnHandleToOS(handle);
    }

    private static native long getHandleFromOS();
    private static native void returnHandleToOS(long handle);

    static Wrapper allocate() {
        return new Handle(getHandleFromOS());
    }
}

Now, when the GC reclaims the space of a wrapper instance, the finalizer makes sure, that the resource is properly returned to the OS.

现在,当 GC 回收包装器实例的空间时,终结器确保资源正确返回给操作系统。

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 disposemechanism and use finalization only as safety-net in case, the clients of your class forget to properly dispose their references:

这听起来不错,但正如其他人已经指出的那样,缺点是,终结本质上是不可靠的:你不知道终结器何时会运行。更糟糕的是:根本无法保证它会运行。因此最好提供一种dispose机制并仅使用终结作为安全网,以防您的类的客户忘记正确处理他们的引用:

class Wrapper {
    private long handle;

    private Handle(long h) {
        handle = h;
    }

    protected void finalize() {
        if( handle != 0 ) returnHandleToOS(handle);
    }

    public void dispose() {
        returnHandleToOS(handle);
        handle = 0;
    }

    private static native long getHandleFromOS();
    private static native void returnHandleToOS(long handle);

    static Wrapper allocate() {
        return new Handle(getHandleFromOS());
    }
}