Java 有析构函数吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/171952/
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-11 10:01:48  来源:igfitidea点击:

Is there a destructor for Java?

javagarbage-collectiondestructor

提问by wai

Is there a destructor for Java? I don't seem to be able to find any documentation on this. If there isn't, how can I achieve the same effect?

Java 有析构函数吗?我似乎无法找到任何关于此的文档。如果没有,我怎样才能达到同样的效果?

To make my question more specific, I am writing an application that deals with data and the specification say that there should be a 'reset' button that brings the application back to its original just launched state. However, all data have to be 'live' unless the application is closed or reset button is pressed.

为了让我的问题更具体,我正在编写一个处理数据的应用程序,并且规范说应该有一个“重置”按钮,可以将应用程序恢复到其刚刚启动的原始状态。但是,除非关闭应用程序或按下重置按钮,否则所有数据都必须是“实时”的。

Being usually a C/C++ programmer, I thought this would be trivial to implement. (And hence I planned to implement it last.) I structured my program such that all the 'reset-able' objects would be in the same class so that I can just destroy all 'live' objects when a reset button is pressed.

作为一个通常是 C/C++ 程序员的我,我认为这很容易实现。(因此我计划最后实现它。)我构建了我的程序,以便所有“可重置”对象都在同一个类中,这样我就可以在按下重置按钮时销毁所有“活动”对象。

I was thinking if all I did was just to dereference the data and wait for the garbage collector to collect them, wouldn't there be a memory leak if my user repeatedly entered data and pressed the reset button? I was also thinking since Java is quite mature as a language, there should be a way to prevent this from happening or gracefully tackle this.

我在想,如果我所做的只是取消引用数据并等待垃圾收集器收集它们,如果我的用户重复输入数据并按下重置按钮,会不会出现内存泄漏?我也在想,既然 Java 作为一种语言已经相当成熟,应该有办法防止这种情况发生或优雅地解决这个问题。

采纳答案by Garth Gilmour

Because Java is a garbage collected language you cannot predict when (or even if) an object will be destroyed. Hence there is no direct equivalent of a destructor.

因为 Java 是一种垃圾收集语言,所以您无法预测对象何时(甚至是否)会被销毁。因此,没有直接等效的析构函数。

There is an inherited method called finalize, but this is called entirely at the discretion of the garbage collector. So for classes that need to explicitly tidy up, the convention is to define a closemethod and use finalize only for sanity checking (i.e. if closehas not been called do it now and log an error).

有一个称为 的继承方法finalize,但这完全由垃圾收集器决定调用。因此,对于需要显式整理的类,约定是定义一个close方法并仅将 finalize 用于完整性检查(即,如果尚未调用close则立即执行并记录错误)。

There was a question that spawned in-depth discussion of finalizerecently, so that should provide more depth if required...

最近有一个问题引发了对 finalize 的深入讨论,因此如果需要,应该提供更深入的讨论...

回答by flicken

No, java.lang.Object#finalizeis the closest you can get.

不,java.lang.Object#finalize是你能得到的最接近的。

However, when (and if) it is called, is not guaranteed.
See: java.lang.Runtime#runFinalizersOnExit(boolean)

但是,不能保证何时(以及是否)调用它。
看:java.lang.Runtime#runFinalizersOnExit(boolean)

回答by Shimi Bandiel

The finalize()function is the destructor.

finalize()功能是析构函数。

However, it should not be normally used because it is invoked after the GCand you can't tell when that will happen (if ever).

但是,通常不应该使用它,因为它是在 GC 之后调用的并且您无法确定何时会发生(如果有的话)。

Moreover, it takes more than one GC to deallocate objects that have finalize().

此外,释放具有finalize().

You should try to clean up in the logical places in your code using the try{...} finally{...}statements!

您应该尝试使用try{...} finally{...}语句在代码中的逻辑位置进行清理!

回答by Nik

The closest equivalent to a destructor in Java is the finalize()method. The big difference to a traditional destructor is that you can't be sure when it'll be called, since that's the responsibility of the garbage collector. I'd strongly recommend carefully reading up on this before using it, since your typical RAIA patterns for file handles and so on won't work reliably with finalize().

最接近 Java 中析构函数的是finalize()方法。与传统析构函数的最大区别在于您无法确定何时调用它,因为这是垃圾收集器的责任。我强烈建议在使用它之前仔细阅读它,因为用于文件句柄等的典型 RAIA 模式不能与 finalize() 可靠地工作。

回答by ddimitrov

Nope, no destructors here. The reason is that all Java objects are heap allocated and garbage collected. Without explicit deallocation (i.e. C++'s delete operator) there is no sensible way to implement real destructors.

不,这里没有析构函数。原因是所有 Java 对象都是堆分配和垃圾收集的。如果没有显式释放(即 C++ 的删除运算符),就没有实现真正析构函数的明智方法。

Java does support finalizers, but they are meant to be used only as a safeguard for objects holding a handle to native resources like sockets, file handles, window handles, etc. When the garbage collector collects an object without a finalizer it simply marks the memory region as free and that's it. When the object has a finalizer, it's first copied into a temporary location (remember, we're garbage collecting here), then it's enqueued into a waiting-to-be-finalized queue and then a Finalizer thread polls the queue with very low priority and runs the finalizer.

Java 确实支持终结器,但它们仅用于保护持有本机资源句柄的对象,如套接字、文件句柄、窗口句柄等。当垃圾收集器收集没有终结器的对象时,它只是标记内存区域是免费的,仅此而已。当对象有终结器时,它首先被复制到一个临时位置(记住,我们在这里是垃圾收集),然后它被排入等待被终结的队列中,然后终结器线程以非常低的优先级轮询队列并运行终结器。

When the application exits, the JVM stops without waiting for the pending objects to be finalized, so there practically no guarantees that your finalizers will ever run.

当应用程序退出时,JVM 不会等待挂起的对象被终结而停止,因此实际上无法保证终结器会一直运行。

回答by McDowell

Use of finalize()methods should be avoided. They are not a reliable mechanism for resource clean up and it is possible to cause problems in the garbage collector by abusing them.

应避免使用finalize()方法。它们不是一种可靠的资源清理机制,滥用它们可能会导致垃圾收集器出现问题。

If you require a deallocation call in your object, say to release resources, use an explicit method call. This convention can be seen in existing APIs (e.g. Closeable, Graphics.dispose(), Widget.dispose()) and is usually called via try/finally.

如果您需要在对象中进行释放调用,比如释放资源,请使用显式方法调用。这种约定可以在现有的 API(例如CloseableGraphics.dispose()Widget.dispose())中看到,并且通常通过 try/finally 调用。

Resource r = new Resource();
try {
    //work
} finally {
    r.dispose();
}

Attempts to use a disposed object should throw a runtime exception (see IllegalStateException).

尝试使用已处理的对象应引发运行时异常(请参阅IllegalStateException)。



EDIT:

编辑:

I was thinking, if all I did was just to dereference the data and wait for the garbage collector to collect them, wouldn't there be a memory leak if my user repeatedly entered data and pressed the reset button?

我在想,如果我所做的只是取消引用数据并等待垃圾收集器收集它们,如果我的用户重复输入数据并按下重置按钮,会不会出现内存泄漏?

Generally, all you need to do is dereference the objects - at least, this is the way it is supposed to work. If you are worried about garbage collection, check out Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning(or the equivalent document for your JVM version).

通常,您需要做的就是取消对对象的引用 - 至少,这是它应该工作的方式。如果您担心垃圾收集,请查看Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning(或您的 JVM 版本的等效文档)。

回答by I GIVE CRAP ANSWERS

Perhaps you can use a try ... finally block to finalize the object in the control flow at which you are using the object. Of course it doesn't happen automatically, but neither does destruction in C++. You often see closing of resources in the finally block.

也许您可以使用 try ... finally 块来完成您正在使用该对象的控制流中的对象。当然,它不会自动发生,但 C++ 中的销毁也不会自动发生。您经常会在 finally 块中看到资源的关闭。

回答by Markus Lux

I fully agree to other answers, saying not to rely on the execution of finalize.

我完全同意其他答案,说不要依赖finalize的执行。

In addition to try-catch-finally blocks, you may use Runtime#addShutdownHook(introduced in Java 1.3) to perform final cleanups in your program.

除了 try-catch-finally 块之外,您还可以使用Runtime#addShutdownHook(在 Java 1.3 中引入)在您的程序中执行最终清理。

That isn't the same as destructors are, but one may implement a shutdown hook having listener objects registered on which cleanup methods (close persistent database connections, remove file locks, and so on) can be invoked - things that would normally be done in destructors. Again - this is not a replacement for destructors but in some cases, you can approach the wanted functionality with this.

这与析构函数不同,但可以实现一个关闭钩子,其中注册了侦听器对象,可以在其上调用清理方法(关闭持久数据库连接、删除文件锁等)——这通常会在析构函数。同样 - 这不是析构函数的替代品,但在某些情况下,您可以使用它来处理所需的功能。

The advantage of this is having deconstruction behavior loosely coupledfrom the rest of your program.

这样做的好处是解构行为程序的其余部分松散耦合

回答by Steve Jessop

First, note that since Java is garbage-collected, it is rare to need to do anything about object destruction. Firstly because you don't usually have any managed resources to free, and secondly because you can't predict when or if it will happen, so it's inappropriate for things that you need to occur "as soon as nobody is using my object any more".

首先,请注意,由于 Java 是垃圾收集的,因此很少需要对对象销毁做任何事情。首先是因为您通常没有任何可释放的托管资源,其次是因为您无法预测它何时或是否会发生,所以它不适用于您需要发生的事情“一旦没有人再使用我的对象”。

You can be notified after an object has been destroyed using java.lang.ref.PhantomReference (actually, saying it has been destroyed may be slightly inaccurate, but if a phantom reference to it is queued then it's no longer recoverable, which usually amounts to the same thing). A common use is:

您可以在使用 java.lang.ref.PhantomReference 销毁对象后收到通知(实际上,说它已被销毁可能有点不准确,但如果对它的幻影引用排队,则它不再可恢复,这通常相当于同样的事情)。一个常见的用途是:

  • Separate out the resource(s) in your class that need to be destructed into another helper object (note that if all you're doing is closing a connection, which is a common case, you don't need to write a new class: the connection to be closed would be the "helper object" in that case).
  • When you create your main object, create also a PhantomReference to it. Either have this refer to the new helper object, or set up a map from PhantomReference objects to their corresponding helper objects.
  • After the main object is collected, the PhantomReference is queued (or rather it may be queued - like finalizers there is no guarantee it ever will be, for example if the VM exits then it won't wait). Make sure you're processing its queue (either in a special thread or from time to time). Because of the hard reference to the helper object, the helper object has not yet been collected. So do whatever cleanup you like on the helper object, then discard the PhantomReference and the helper will eventually be collected too.
  • 将类中需要销毁的资源分离到另一个辅助对象中(请注意,如果您所做的只是关闭连接,这是一种常见情况,则不需要编写新类:在这种情况下,要关闭的连接将是“帮助对象”)。
  • 创建主对象时,还要为其创建 PhantomReference。要么让 this 引用新的 helper 对象,要么设置一个从 PhantomReference 对象到它们相应的 helper 对象的映射。
  • 收集主对象后, PhantomReference 被排队(或者更确切地说它可能被排队 - 就像终结器一样,无法保证它永远如此,例如,如果 VM 退出,则它不会等待)。确保您正在处理其队列(在特殊线程中或不时)。由于对辅助对象的硬引用,辅助对象尚未被收集。所以对辅助对象做任何你喜欢的清理,然后丢弃 PhantomReference,辅助对象最终也会被收集。

There is also finalize(), which looks like a destructor but doesn't behave like one. It's usually not a good option.

还有 finalize(),它看起来像一个析构函数,但行为却不像析构函数。这通常不是一个好的选择。

回答by John Nilsson

If it's just memory you are worried about, don't. Just trust the GC it does a decent job. I actually saw something about it being so efficient that it could be better for performance to create heaps of tiny objects than to utilize large arrays in some instances.

如果这只是您担心的记忆,请不要担心。只要相信 GC 它做得不错。我实际上看到了一些关于它如此高效的东西,以至于在某些情况下,创建小对象堆比使用大型数组可能更好地提高性能。