【问题标题】:why allocation phase can be increased if we override finalize method?如果我们覆盖 finalize 方法,为什么可以增加分配阶段?
【发布时间】:2016-12-29 11:15:10
【问题描述】:

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

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

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

【问题讨论】:

  • 我会先对该主题进行一些研究;并检查您是否找到关于此的 任何内容 ... 写于 2000 年左右之后。请记住,最着名的认为 Block 工作......就像过去 15 年一样。 从那时起,java平台发生了很多
  • 我不明白为什么分配会更贵。清理创建对象以将对象添加到终结队列。
  • 分配可能需要更长时间,因为它更有可能必须等待由非平凡的finalize() 覆盖引起的 GC 周期。
  • @GhostCat 这是“Bloch”,而不是“Block”。
  • 另外,Effective Java 是,“喜欢”,八岁,这并不重要,因为 建议是有效的!为什么你认为老是坏事,更不用说夸大年龄了?

标签: java garbage-collection java-memory-model finalize finalization


【解决方案1】:

我已经搜索过原文:

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

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-16
    • 2014-04-28
    • 2017-11-01
    • 2020-12-31
    • 1970-01-01
    • 2016-03-06
    • 2012-04-21
    相关资源
    最近更新 更多