为什么终结器会有“严重的性能损失”?

发布于 2024-09-01 16:05:50 字数 95 浏览 11 评论 0原文

有效的Java 说:

使用终结器会严重影响性能。

为什么使用终结器销毁对象的速度较慢?

Effective Java says :

There is a severe performance penalty for using finalizers.

Why is it slower to destroy an object using the finalizers?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

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

发布评论

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

评论(6

合约呢 2024-09-08 16:05:50

由于垃圾收集器的工作方式。为了提高性能,大多数 Java GC 使用复制收集器,其中短期对象被分配到“eden”内存块中,当需要收集该代对象时,GC 只需复制要收集的对象。仍然“活着”到更永久的存储空间,然后它可以一次性擦除(释放)整个“eden”内存块。这是高效的,因为大多数 Java 代码将创建数千个对象实例(装箱基元、临时数组等),其生命周期仅为几秒。

但是,当您混合使用终结器时,GC 不能简单地立即擦除整个生成代。相反,它需要找出该代中需要终结的所有对象,并将它们排队到实际执行终结器的线程上。与此同时,GC无法有效地完成对象的清理。因此,它要么必须让它们的存活时间比应有的时间长,要么必须延迟收集其他对象,或者两者兼而有之。另外,您还有实际执行终结器的任意等待时间。

所有这些因素加起来会造成显着的运行时损失,这就是为什么通常首选确定性终结(使用 close() 方法或类似的方法来显式终结对象的状态)。

Because of the way the garbage collector works. For performance, most Java GCs use a copying collector, where short-lived objects are allocated into an "eden" block of memory, and when the it's time for that generation of objects to be collected, the GC just needs to copy the objects that are still "alive" to a more permanent storage space, and then it can wipe (free) the entire "eden" memory block at once. This is efficient because most Java code will create many thousands of instances of objects (boxed primitives, temporary arrays, etc.) with lifetimes of only a few seconds.

When you have finalizers in the mix, though, the GC can't simply wipe an entire generation at once. Instead, it needs to figure out all the objects in that generation that need to be finalized, and queue them on a thread that actually executes the finalizers. In the meantime, the GC can't finish cleaning up the objects efficiently. So it either has to keep them alive longer than they should be, or it has to delay collecting other objects, or both. Plus you have the arbitrary wait time of actually executing the finalizers.

All these factors add up to a significant runtime penalty, which is why deterministic finalization (using a close() method or similar to explicitly finalize the object's state) is usually preferred.

城歌 2024-09-08 16:05:50

实际上遇到过这样一个问题:

在 Sun HotSpot JVM 中,终结器是在一个被赋予固定的低优先级的线程上处理的。在高负载应用程序中,创建需要终结的对象的速度很容易快于低优先级终结线程处理它们的速度。同时,终结挂起对象使用的堆上空间不可用于其他用途。最终,您的应用程序可能会花费所有时间进行垃圾收集,因为所有可用内存都被待完成的对象使用。

当然,除了《Effective Java》中描述的不使用终结器的其他许多原因之外。

Having actually run into one such problem:

In the Sun HotSpot JVM, finalizers are processed on a thread that is given a fixed, low priority. In a high-load application, it's easy to create finalization-required objects faster than the low-priority finalization thread can process them. Meanwhile, the space on the heap used by the finalization-pending objects is unavailable for other uses. Eventually, your application may spend all of its time garbage collecting, because all of the available memory is in use by objects pending finalization.

This is, of course, in addition to the other many reasons to not use finalizers that are described in Effective Java.

一口甜 2024-09-08 16:05:50

我刚刚从办公桌上拿起我的《Effective Java》,想看看他指的是什么。

如果你读过第 2 章第 6 节,他会详细介绍各种热门表演。

您无法知道终结器何时运行,甚至根本不知道它是否会运行。因为这些资源可能永远不会被占用,所以您将不得不使用更少的资源来运行。

我建议您阅读本节的全部内容 - 它对事情的解释比我在这里鹦鹉学舌的要好得多。

I just picked up my copy Effective Java off my desk to see what he's referring to.

If you read Chapter 2, Section 6, he goes into good detail about the various performance hits.

You can't know when the finalizer will run, or even if it will at all. Because those resources may never be claimed, you will have to run with fewer resources.

I would recommend reading the entirety of the section - it explains things much better than I can parrot here.

时光倒影 2024-09-08 16:05:50

如果您阅读 的文档密切关注finalize(),您会注意到终结器使对象能够防止被GC收集。

如果不存在终结器,则可以简单地删除该对象并且不需要更多关注。但是,如果有终结器,则需要在事后检查对象是否再次“可见”。

在不知道当前Java垃圾回收是如何实现的(实际上,因为有不同的Java实现,所以也有不同的GC),你可以假设如果一个对象有终结器,GC必须做一些额外的工作,因为的这个功能。

If you read the documentation of finalize() closely, you will notice that finalizers enable an object to prevent being collected by the GC.

If no finalizer is present, the object simply can be removed and does not need any more attention. But if there is a finalizer, it needs to be checked afterwards, if the object didn't become "visible" again.

Without knowing exactly how the current Java garbage collection is implemented (actually, because there are different Java implementations out there, there are also different GCs), you can assume that the GC has to do some additional work if an object has a finalizer, because of this feature.

放飞的风筝 2024-09-08 16:05:50

我的想法是这样的:
Java是一种垃圾收集语言,它根据自己的内部算法来释放内存。 GC 每隔一段时间就会扫描堆,确定哪些对象不再被引用,并取消分配内存。
终结器会中断此过程并强制在 GC 周期之外重新分配内存,从而可能导致效率低下。
我认为最佳实践是仅在绝对必要时才使用终结器,例如释放文件句柄或关闭数据库连接,这些应该确定性地完成。

My thought is this:
Java is a garbage collected language, which deallocates memory based on its own internal algorithms. Every so often, the GC scans the heap, determines which objects are no longer referenced, and de-allocates the memory.
A finalizer interrupts this and forces the deallocation of memory outside of the GC cycle, potentially causing inefficiencies.
I think best practices are to use finalizers only when ABSOLUTELY necessary such as freeing file handles or closing DB connections which should be done deterministically.

十二 2024-09-08 16:05:50

我能想到的原因之一是,如果您的资源都是 Java 对象而不是本机代码,则不需要显式内存清理。

One reason I can think of is that explicit memory cleanup is unnecessary if your resources are all Java Objects, and not native code.

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