您如何看待Sonar的糟糕练习 - Finalizer只会使字段无效?

时间:2013-09-03 11:18:25

标签: java garbage-collection sonarqube

当您执行以下操作时,

@Override
protected void finalize() throws Throwable {
    ////////////////////////

    this.aVeryBigComponent = null;

    ////////////////////////

    super.finalize();
}

声纳抱怨

  

糟糕的做法 - Finalizer只会使字段为空

     

findbugs:FI_FINALIZER_ONLY_NULLS_FIELDS

     

除了字段外,此终结器不执行任何操作。这是完全没有意义的,并且要求对象被垃圾收集,最终确定,然后再次收集垃圾。你应该删除finalize方法。

只要我知道将字段设置为null有助于垃圾收集器在第一次运行/生成中销毁对象。如果我没有将该字段设置为null,则该对象可能会被发送到第二代并等待更多。

您怎么看?

6 个答案:

答案 0 :(得分:8)

  

如果我没有将该字段设置为null,那么该对象可能会被发送到第二代并等待更多。

如果您没有终结者 ,那么您的对象将有资格进行垃圾收集,并且其字段不会被计为GC根,因此其他对象可能符合条件同时进行垃圾收集。

即使你需要终结器,除非终结器恢复对象,否则最终对象仍然有资格进行垃圾收集,因此其字段不会使其他对象保持活动状态。

非常非常很难用Java编写终结器...如果它只是将字段设置为null,那肯定是个坏主意。 (几乎可以肯定伤害表现而不是帮助它。)

答案 1 :(得分:2)

  

具有终结器的对象(具有非平凡终结的对象()   方法)与没有对象的对象相比有很大的开销   终结者,应谨慎使用。可完成的对象是   分配较慢,收集较慢。在分配时,   JVM必须使用垃圾收集器注册任何可完成的对象,   和(至少在HotSpot JVM实现中)可终结对象   必须遵循比大多数其他对象更慢的分配路径。   同样,可完成对象的收集速度也较慢。它需要   在a之前至少有两个垃圾收集周期(在最好的情况下)   可以回收可终结对象,垃圾收集器必须   做额外的工作来调用终结器。结果是花费更多时间   分配和收集对象以及对垃圾施加更多压力   收集器,因为无法访问的可终结对象使用的内存   保留更长时间。将其与终结器不同的事实相结合   保证在任何可预测的时间范围内运行,甚至可以运行   你可以看到相对较少的情况   最终确定是正确使用的工具。

     

如果您必须使用终结器,可以遵循一些指导原则   这将有助于遏制损害。限制可终结的数量   对象,这将最小化必须招致的对象的数量   最终确定的分配和收集成本。组织你的   类,以便可终结对象不包含其他数据   最小化后可完成对象中占用的内存量   它们变得无法到达,因为它们之前可能会有很长的延迟   实际上回收了。特别要注意延长可终结性   标准库中的类。

有关完整文章,请参阅http://www.ibm.com/developerworks/java/library/j-jtp01274/index.html

希望有所帮助

答案 2 :(得分:2)

实际上,它会与你的建议相反。

  

我知道将字段设置为null有助于垃圾收集器在第一次运行/生成时销毁对象。

使用终结器意味着在终结线程中调用终结器之后才能收集这两个对象。

  

如果我没有将该字段设置为null,那么该对象可能会被发送到第二代并等待更多。

如果您不使用终结器,则可以同时清理这两个对象。

答案 3 :(得分:0)

声纳是正确的 - 您不必为GC做出正确的操作设置为null。

“只要我知道将字段设置为null有助于垃圾收集器在第一次运行/生成中销毁对象。” - 据我所知,这一切都不重要。 GC比你聪明得多。

答案 4 :(得分:0)

当您的实例即将收集垃圾时,将调用您实例上的

finalize()方法。

这意味着,您实例的所有字段也将被垃圾收集,因此无需明确这样做。

答案 5 :(得分:0)

无法保证何时,甚至调用终结器。 如果对象超出范围,则它是gc的候选对象。如果它有终结器,则会在对象被销毁之前调用它。

终结器可以将一个对象带回范围,(它可能会调用一些寄存器(this)方法)所以也许这就是为什么垃圾收集器不会删除该传递中的对象,而是等到下一轮确定对象是否仍然超出范围。 如果它没有终结器,gc可以确定它没有被带回范围,因此删除它是安全的。

此外,不要混淆设置字段为null以删除对该字段的引用,以及您所在的终结器的对象。这是两个可以在不同时间进行垃圾回收的单独对象。