2

我听说在 Joshua Bloch 写的书中,如果我们重写 finalize 方法,分配和内存收集可能会增加到 430 倍。

对我来说很明显,内存收集可能会更慢,因为 gc 需要额外的迭代来释放内存。

但是为什么分配阶段可以增加呢?

4

1 回答 1

2

我已经搜索了原始声明:

在我的机器上,创建和销毁一个简单对象的时间约为 5.6 ns。添加终结器会将时间增加到 2,400 ns。换句话说,使用终结器创建和销毁对象的速度大约慢了 430 倍。

所以这不是一个一般性的陈述,而只是一份证据报告,表明它背后有一个模式,而不是这个数字是可重现的。当使用不那么微不足道的对象或更多的对象时,这个因素可能会改变。

当然,这些成本取决于最终确定的实际实施方式。在 HotSpot 中,每次创建具有非平凡方法的对象时,Finalizer都会通过调用该方法来创建一个实例。Finalizer.registerfinalize()

这可能意味着比仅仅分配两个对象而不是一个对象要多得多的成本。这些Finalizer实例将被强链接,这对于防止实例本身的集合是必要的Finalizer,并且它们具有对构造对象的引用。换句话说,无论最初分配的对象有多局部,新对象都会逃逸,从而阻碍了许多后续的优化。

当谈到“破坏”时,回收一个普通的对象是无操作的。不会采取任何行动,事实上,不可能对无法访问的对象做任何事情,因为它是unreachable。特殊的可达性状态只能通过拥有一个可达Reference对象来遇到,比如Finalizer上面提到的对象,它持有对特定对象的引用(而对象不是通过任何其他普通引用遇到的。然后,Reference对象可以入队,之后哪个(其中一个)终结器线程可以采取适当的行动。

当然,将“不采取行动”与任何其他行动进行比较可能会导致任意因素。绝对数字是 2,400ns,这对于涉及将对象入队并通知另一个线程轮询队列的操作是合理的。

于 2017-01-11T16:42:16.403 回答