一个对象成为可终结对象的前期成本是什么?

9

在Java中,关于可终结对象的讨论通常会涉及当不可快速回收可终结对象(和它们相关的资源)时发生的常见间接成本。

目前,我更感兴趣的是可终结性实际的直接成本,包括内存方面和对象分配时间方面。我在许多地方看到了对这种成本存在的间接引用,例如Oracle的最终化内存保留问题文章中提到:

当分配obj时,JVM会在内部记录obj是可终结的。这通常会减慢现代JVM具有的快速分配路径。

JVM如何记录对象实例为可终结对象,进行此操作的内存和性能成本是什么?

对于那些对我具体应用程序感兴趣的人:

我们生产并保留了数百万极轻量级的对象;添加单个指针到这些对象是非常昂贵的,因此我们已经做了很多工作来从中删除指针,而是使用打包在字段的子集中的较小数字 ID。解压缩该数字允许从存储它们的 Map 中检索具有该 ID 的共享不可变属性。
剩下的问题是如何处理不再使用的属性值的垃圾回收。
考虑过的一种策略是使用引用计数;当创建对象并检索值的池化 ID 时,该值的引用计数将增加;当它不再使用时,必须将其减少。
确保发生此减量的一个选项是添加以下 finalize 方法:
public void finalize() {
    Pool.release(getPropertyId());
}

然而,如果成为可终结对象的行为意味着必须保留对该对象的附加指针,则对于此应用程序来说,成为可终结对象的前期成本将被认为是高昂的。如果这意味着必须分配额外的对象,则几乎肯定过高...因此,我的问题是:成为可终结的直接前期成本是多少?

依赖对象的终结是否是一种不好的做法?我的意思是,finalize() 方法从来没有保证会被调用,对吗? - vikingsteve
你可能想要管理自己的对象池,而不是依赖于JVM。根据你需要同时使用多少个对象,你可能会发现完全避免分配/垃圾回收/终结开销可以获得巨大的性能提升。 - Ted Hopp
你能否使用引用队列而不是finalization呢?参见https://dev59.com/-mYq5IYBdhLWcg3weQgy,了解它的工作原理。 - Louis Wasserman
@PeterLawrey 我想这可能是事实。 但是,这些对象往往具有非常长的生命周期(以小时为单位)。 使用模式可能会有所不同,用户可以要求重建约2000万个对象的整个数据库,但更常见的情况是每次只会丢失并重建几千个对象。由于可能会保留对已删除对象的少量引用,因此我们希望它们的属性也能够保持可检索性。 - Theodore Murdock
通常情况下,您需要使您的其中一个类扩展WeakReference,这样您就不会有任何额外的对象。但即便如此,与终结相比,该额外信息通常被认为是显著更便宜的。 - Louis Wasserman
显示剩余9条评论
1个回答

8

Finalizers非常糟糕,不仅因为保留问题,而且从性能角度来看也很糟糕。

在Oracle JDK / OpenJDK中,具有finalize方法的对象由Finalizer实例支持,这是java.lang.ref.Reference的子类。

所有终结器都在对象构造函数的末尾以两个步骤注册:从Java到VM的调用(from Java to VM),然后调用(Finalizer.register())。 JIT编译器无法内联此双重转换Java->VM->Java。但最糟糕的是,终结器的构造函数在(全局锁)下创建了一个链接列表!(facepalm)

最终器在内存占用方面也很糟糕:除了所有的引用字段外,它们还有两个额外的字段nextprev

幻象引用比终结器好得多:

  • 它们的构造不需要转换到VM并返回,可以内联;
  • 除从java.lang.ref.Reference继承的字段外,它们没有额外的字段;
  • 不进行全局同步。

这个基准测试比较了可终结对象和由幻象引用支持的对象的分配速度:

Benchmark               Mode  Cnt       Score      Error   Units
Finalizer.finalizable  thrpt    5    2171,312 ± 1469,705  ops/ms
Finalizer.phantom      thrpt    5   61280,612 ±  692,922  ops/ms
Finalizer.plain        thrpt    5  225752,307 ± 7618,304  ops/ms

在OpenJDK中不修补全局锁的原因是什么? - qwwdfsad
我会说没有修补的理由。为什么要关心那些不建议使用的遗留代码呢? - apangin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接