jvm 可定案对象的前期成本是多少?

9q78igpj  于 2022-11-07  发布在  其他
关注(0)|答案(1)|浏览(115)

在Java中讨论可finalizable对象时,通常会讨论当可finalizable对象(及其相关资源)不能被快速垃圾收集时所发生的常见间接成本。
目前,我更感兴趣的是可finalizable的实际直接成本是多少,包括内存成本和对象分配时间成本。我在很多地方看到过间接的引用,例如Oracle's article on finalization memory retention issues注解:
obj被分配时,JVM在内部记录obj是可finalizable的。这通常会减慢现代JVM的快速分配路径。

JVM如何记录一个对象示例是可finalizable的,这样做的内存和性能成本是多少?

对于那些对我的具体应用感兴趣的人:
我们生产并保留了数百万个难以置信的轻质物体;向这些对象添加一个指针的代价非常高,因此我们做了大量工作来删除指针,而不是使用压缩到字段位子集中的较小数字id。解压缩数字允许从使用Map存储它们的Pool中检索具有该id的共享不可变属性。
剩下的问题是如何处理不再使用的属性值的垃圾回收。
已经考虑的一种策略是使用引用计数;当对象被创建并检索值的汇集ID时,该值的引用计数递增;当不再使用它时,它必须递减。
确保发生这种递减的一个选项是添加以下finalize方法:

public void finalize() {
    Pool.release(getPropertyId());
}

然而,如果finalizable的行为本身就意味着必须保留指向对象的额外指针,那么finalizable的前期成本对于这个应用程序来说就很高了。如果它意味着必须分配额外的对象,那么几乎可以肯定成本太高了......因此,我的问题是:可定案的直接前期成本是多少?

zpf6vheq

zpf6vheq1#

终结器糟糕不仅是因为保留问题,而且从性能Angular 来看也是如此。
在Oracle JDK / OpenJDK中,具有finalize方法的对象由Finalizerjava.lang.ref.Reference的子类)的示例支持。
所有终结器都在对象构造函数的末尾注册,分两步进行:一个从Java到VM的调用,然后调用Finalizer.register()。JIT编译器不能内联Java-〉VM-〉Java的这种双重转换。但最糟糕的是Finalizer的构造函数在全局锁下生成了一个链表!(facepalm)
终结器在内存占用方面也不好:除了所有参考字段外,它们还有两个额外字段:nextprev中的一个或多个。
PhantomReferences比终结器好得多:

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

This benchmark比较可finalizable对象和PhantomReference支持的对象的分配速度:

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

相关问题