我听说在Joshua Bloch的书中写道,如果我们重写finalize方法,则分配和内存收集可能会增加到430次。
对我来说很明显,内存收集的工作可能会变慢,因为gc需要进行额外的迭代才能释放内存。
但是为什么可以增加分配阶段?
我已经搜索了原始语句:
在我的机器上,创建和销毁简单对象的时间约为5.6 ns。添加终结器会将时间增加到2,400 ns。换句话说,使用终结器创建和销毁对象要慢430倍。
因此,这并不是一般性的陈述,而只是一份证据报告,表明背后存在某种模式,而不是数字是可重复的。当使用不那么平凡的对象或仅使用更多对象时,此因素可能会改变。
当然,这些成本取决于最终实施的实际方式。在HotSpot中,每次Finalizer创建Finalizer.register具有非平凡finalize()方法的对象时,都会通过调用该方法来创建的实例。
Finalizer
Finalizer.register
finalize()
这可能意味着比仅分配两个对象而不是分配一个对象要多得多的成本。这些Finalizer实例将被牢固地链接,这对于防止Finalizer实例本身的收集是必需的,并且它们具有对构造对象的引用。换句话说,不管最初对象分配的位置如何,新对象都会 逃逸 ,从而阻碍了许多后续优化。
当涉及到“破坏”时,收回一个普通的物体是不容置疑的。不将采取行动,事实上,这是不可能做任何事情不可达的对象,因为它是 不可达 。只能通过拥有一个可达Reference对象(如上述Finalizer对象)来保存特殊的可达性状态,如上面提到的对象,该对象持有对特定对象的引用(而其他任何普通引用都没有遇到该Reference对象。然后,可以将该对象排队,之后终结器线程中的哪一个可以采取适当的操作。
Reference
当然,将“无行动”与任何其他行动进行比较会导致任意因素。绝对数为2,400ns,对于涉及使一个对象入队并通知另一个线程轮询队列的操作是合理的。