可最终确定对象的前期成本是多少? [英] What is the up-front cost of an object being finalizable?

查看:121
本文介绍了可最终确定对象的前期成本是多少?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java中可终结对象的讨论通常讨论当最终化对象(及其相关资源)无法快速垃圾收集时发生的常见间接成本。

Discussions of finalizable objects in Java typically discuss the common indirect costs that happen when finalizable objects (and their associated resources) cannot be quickly garbage collected.

我是目前,更感兴趣的是,无论是在内存方面还是在对象分配时间内,可以最终确定的实际直接成本。我已经在很多地方看到了这种成本存在的倾向性,例如, Oracle关于最终化内存保留问题的文章说明:

I'm more interested, at the moment, in what the actual direct cost of being finalizable is, both in memory terms, and in object allocation time. I've seen oblique references to the existence of such a cost in a number of places, for example, Oracle's article on finalization memory retention issues notes:


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

When obj is allocated, the JVM internally records that obj is finalizable. This typically slows down the otherwise fast allocation path that modern JVMs have.

JVM如何记录对象实例这样做会有什么样的内存和性能成本?

对于那些对我的特定应用感兴趣的人:

For those interested in my specific application:

我们生产和保留了数以百万计的轻巧物体;添加一个指向这些对象的指针是非常昂贵的,所以我们已经做了很多工作来删除它们的指针,而是使用较小的数字ID打包到字段的一部分位。解包该数字允许从使用Map存储它们的池中检索具有该id的共享不可变属性。

We produce and retain millions of incredibly lightweight objects; adding a single pointer to these objects is incredibly costly, so we've done a fair bit of work to remove pointers from them, instead using smaller numeric ids packed into a subset of the bits of a field. Unpacking the number allows the shared immutable property with that id to be retrieved from a Pool that stores them using a Map.

剩下的问题是如何处理垃圾收集不再使用的属性值。

The remaining question is how to handle the garbage collection of property values that are no longer used.

已经考虑的一种策略是使用引用计数;当创建对象并检索值的池化id时,该值的引用计数递增;当它不再使用时,它必须递减。

One strategy that has been considered is using reference counting; when objects are created and retrieve the pooled id for a value, the reference count for that value is incremented; when it is no longer used, it must be decremented.

确保发生这种减量的一个选项是添加以下最终方法:

One option to ensure this decrement happens is to add the following finalize method:

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

但是,如果可最终化的行为意味着另外指向必须保留对象,对于此应用程序,可最终确定的前期成本将被视为高。如果它意味着必须分配额外的对象,那几乎肯定会过高......因此,我的问题是:最终化的直接前期成本是多少?

However, if the very act of being finalizable means that an additional pointer to the object must be kept, the up-front cost of being finalizable would be considered high for this application. If it means additional objects must be allocated, it would almost certainly be too high...hence, my question: what is the direct up-front cost of being finalizable?

推荐答案

终结者糟糕不仅是因为保留问题,而且还从性能角度来看。

Finalizers are awful not only because of retention issues, but from performance perspective, too.

在Oracle JDK / OpenJDK中,具有 finalize 方法的对象由 Finalizer java.lang.ref.Reference

In Oracle JDK / OpenJDK the objects with finalize method are backed by the instances of Finalizer, the subclass of java.lang.ref.Reference.

所有终结器都在对象的构造函数的末尾注册,分两步:调用从Java到VM ,然后调用 Finalizer.register()。 JIT编译器无法内联这种双转换Java-> VM-> Java。但最糟糕的是,Finalizer的构造函数在全球锁定! (facepalm)

All Finalizers are registered at the end of object's contructor in two steps: a call from Java to VM followed by the invocation of Finalizer.register(). This double transition Java->VM->Java cannot be inlined by JIT compiler. But the worst thing is that Finalizer's constructor makes a linked list under the global lock! (facepalm)

终结器在内存占用方面也很糟糕:除了所有参考字段外,它们还有两个额外字段 next 上游

Finalizers are also bad in terms of memory footprint: in addition to all Reference fields they have two extra fields: next and prev.

PhantomReferences比终结者好得多:

PhantomReferences are much better than finalizers:


  • 他们的构造不需要转换到VM并且可以内联;

  • 他们除了继承自<之外没有额外的字段code> java.lang.ref.Reference ;

  • 没有进行全局同步。

  • their construction does not require transition to VM and back and can be inlined;
  • they do not have extra fields besides inherited from java.lang.ref.Reference;
  • no global synchronization is made.

此基准比较可终结对象的分配速度和PhantomReference支持的对象:

This benchmark compares the allocation speed of finalizable objects and the objects backed by 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

这篇关于可最终确定对象的前期成本是多少?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆