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

时间:2010-05-18 18:52:21

标签: java performance memory-management finalizer object-destruction

有效的Java说:

  

使用终结器会有严重的性能损失。

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

6 个答案:

答案 0 :(得分:23)

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

如果混音中有终结器,GC不能简单地一次擦拭整整一代。相反,它需要弄清楚那一代中需要最终确定的所有对象,并将它们排队到实际执行终结器的线程上。与此同时,GC无法有效地清理对象。因此要么让它们保持活动的时间超过它们应该的时间,要么它必须延迟收集其他物体,或两者兼而有之。另外,你有实际执行终结器的任意等待时间。

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

答案 1 :(得分:10)

实际遇到一个这样的问题:

在Sun HotSpot JVM中,终结器在给定固定的低优先级的线程上处理。在高负载应用程序中,与低优先级的终结线程可以处理它们相比,可以更容易地创建所需的终结所需对象。同时,finalization-pending对象使用的堆上的空间不可用于其他用途。最终,您的应用程序可能会花费所有时间进行垃圾收集,因为待完成的对象正在使用所有可用内存。

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

答案 2 :(得分:2)

我刚拿起我的副本有效Java离开我的桌子,看看他指的是什么。

如果您阅读第2章第6节,他会详细介绍各种性能点击。

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.

我建议阅读整个部分 - 它解释的事情比我在这里鹦鹉学得好得多。

答案 3 :(得分:1)

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

答案 4 :(得分:1)

如果您仔细阅读finalize()的文档,您会注意到终结器使对象无法被GC收集。

如果没有终结器,则可以删除该对象,不需要再注意。但是如果有一个终结器,那么如果对象没有再次“可见”,则需要进行检查。

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

答案 5 :(得分:0)

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