Java 中终结的目的是什么?

发布于 2024-08-24 20:48:19 字数 161 浏览 13 评论 0原文

我对终结的理解是这样的:

为了清理或回收对象占用的内存,垃圾收集器开始起作用。 (自动调用?)

然后垃圾收集器取消引用该对象。有时,垃圾收集器无法访问该对象。然后调用 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

习惯成性 2024-08-31 20:48:20

垃圾收集器在后台自动工作(虽然可以显式调用它,但这种需要应该很少)。它基本上只清理未被其他对象引用的对象(当然,整体情况更复杂,但这是基本思想)。因此它不会更改任何活动对象中的任何引用。如果无法从任何活动对象访问某个对象,则意味着可以安全地对其进行垃圾回收。

终结意味着清理对象获取的资源(不是内存,而是其他资源,例如文件句柄、端口、数据库连接等)。然而,它并没有真正解决:-(

  • 事实上,什么时候调用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 :-(

  • it is unpredictable when finalize() will be called
  • in fact, there is no guarantee that finalize() 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.

各自安好 2024-08-31 20:48:20

来自这篇文章

任何类的实例
实现finalize()方法是
通常称为可终结对象。他们
不会立即被回收
Java 垃圾收集器
不再引用。相反,
Java 垃圾收集器附加
对象到一个特殊的队列
最终确定过程。通常是
由一个称为 a 的特殊线程执行
一些 Java 上的“参考处理程序”
虚拟机。在此期间
最终确定过程,“Finalizer”
线程将执行每个finalize()
对象的方法。仅在之后
顺利完成
Finalize() 方法将一个对象
移交Java垃圾
回收其空间的集合
通过“未来”垃圾收集。

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

另外,Sun 的这篇文章有一些很好的图表解释了该过程。

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.

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

天涯离梦残月幽梦 2024-08-31 20:48:20

没有。仅当垃圾收集器尝试回收您的对象时,才会运行 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.

心安伴我暖 2024-08-31 20:48:20

实际上,这是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. :)

¢蛋碎的人ぎ生 2024-08-31 20:48:20

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

class Wrapper {
    private long handle;

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

    private static native long getHandleFromOS();

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

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

为了让您的代码在这种情况下得到清理,需要使用 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());
    }
}

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

这听起来不错,但正如其他人已经指出的那样,缺点是,终结本质上是不可靠的:您不知道终结器何时运行。更糟糕的是:根本无法保证它会运行。因此,最好提供一个 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());
    }
}

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

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.

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

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.

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:

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());
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文