为什么终结器有“严重的性能损失”?
2022-09-01 15:49:08
有效的Java说:
使用终结器会严重降低性能。
为什么使用终结器销毁对象的速度较慢?
有效的Java说:
使用终结器会严重降低性能。
为什么使用终结器销毁对象的速度较慢?
因为垃圾回收器的工作方式。为了提高性能,大多数 Java GC 使用复制收集器,其中短期对象被分配到“eden”内存块中,当需要收集该代对象时,GC 只需要将仍然“活着”的对象复制到更永久的存储空间中,然后它可以立即擦除(释放)整个“eden”内存块。这是有效的,因为大多数Java代码将创建数千个对象实例(盒装基元,临时数组等),生存期仅为几秒钟。
但是,当您在组合中使用终结器时,GC不能简单地一次擦除整整一代。相反,它需要找出该代中需要完成的所有对象,并将它们排队到实际执行终结器的线程上。与此同时,GC无法有效地完成对象的清理。因此,它要么必须使它们存活的时间超过应有的时间,要么必须延迟收集其他对象,或者两者兼而有之。另外,您有实际执行终结器的任意等待时间。
所有这些因素加起来都会造成明显的运行时损失,这就是为什么确定性终结(使用方法或类似方法显式完成对象状态)通常是首选的原因。close()
实际上遇到了一个这样的问题:
在 Sun HotSpot JVM 中,终结器在给定固定的低优先级线程上进行处理。在高负载应用程序中,创建需要终结的对象的速度很容易超过低优先级终结线程处理它们的速度。同时,finalization 挂起对象使用的堆上的空间不可用于其他用途。最终,应用程序可能会将所有时间都花在垃圾回收上,因为所有可用内存都由等待最终确定的对象使用。
当然,这是除了不使用 Effective Java 中描述的终结器的其他许多原因之外。