【问题标题】:How do final fields NOT leak memory?最终字段如何不泄漏内存?
【发布时间】:2014-06-10 15:50:04
【问题描述】:

多年来,我一直毫无疑问地使用final 关键字来表示在实例/类的生命周期内不应更改的字段。我突然想到了这个……

所以给出这个例子:

public class TestFinalGC{

    private TestFinalGC(){}

    private final Object obj = new Object();

     public static void main(String []args){
         TestFinalGC instance = new TestFinalGC();
         // instance Ref -> actual instance ->? obj ref-> actual obj
         System.out.println(instance.obj);
         instance = null;
         //say GC makes sweep here... what happens?
         //lets assume theres more code, obj would obviously be eligible for GC on app exit.
     }
}

obj 成员如何不在这里泄漏? final 字段是否会自动为 WeakReferences,这样如果对父级的强引用为空,它们就有资格进行垃圾回收?

The JLS does not seem to note anything special about final

更新:

所以我的这个问题是建立在“可达性”和强/弱引用密切相关的前提下的。有this confusing oracle doc on reachability 让我相信嵌套引用应该始终是“高度可达的”。因此,我在所有对象中都将嵌套对象引用设为空,但我收到的所有 cmets 显然不应该是这种情况。

那么,关于“可达性”,如果父引用不再可达,嵌套对象引用是否不再被视为“可达”?

确实可能这个问题的前提是不正确的,但是这里还是有一些耐人寻味的信息需要巩固。

【问题讨论】:

  • 否,但答案仍然有效。 final 并没有什么特别之处,使其无法进行垃圾回收。
  • @rpg711 仅当您排除可达性时。当 final 字段本身不再可访问时,它就有资格进行 GC。到那时,它所引用的所有内容都变得不可访问并且可能符合条件(除非,例如,它可以通过另一个引用访问)。
  • Root->instance 被清除时,包含final 字段的实例不再可访问,因此无论final 字段引用什么也不再可访问,只要没有其他引用它。不可访问与弱引用不同。
  • 您可以将对象视为村庄,并将引用视为从一个村庄到另一个村庄的单向道路。如果你只能从 A 村走一条路去 B 村,而且如果没有通往 A 村的路(即 A 无法到达),那么 B 村当然也无法到达。 GC 将因此收集 A 和 B。

标签: java memory-leaks garbage-collection final


【解决方案1】:

正如 Makoto 所建议的,就 GC 而言,变量声明中的 final 没有什么特别之处。在您的示例代码中

private final Object obj = new Object();

将与垃圾同时收集

private Object obj = new Object();

两者都是强引用,但与它们的父类 TestFinalGC 实例一起被无效和垃圾收集。那是因为当实例被 GC'd 时,引用字段也被销毁并且引用不再存在。 obj 的引用计数因此减一。

但是,你应该写类似的东西

Object x = myTestFinalGC.obj; // only works if your obj is not private, of course

然后该对象将不会被垃圾回收,因为它仍然有一个引用徘徊(假设这一特定代码行在另一个类实例中,当 myTestFinalGC 被垃圾回收时该类实例仍然存在。

tl;dr:当硬引用计数降至零时(当然,收集器运行),内存分配被垃圾收集。 final 并没有改变这个事实。

【讨论】:

  • 当硬引用计数降至零时,内存分配会被垃圾回收:不,这是不正确的。可达性是最重要的,而不是引用计数。否则,GC 永远不会收集具有循环引用的对象图。
  • 我尽量简单地解释这个概念。 OP 似乎在理解 GC 的条件方面存在问题。所以我不想让事情进一步复杂化。感谢您指出这一点。
  • @velis 我不会说问题,只是说这个问题所基于的前提很可能是不正确的。我还想指出,我并不完全在寻找简单。有一段时间,我也认为不可访问的对象有资格进行 GC,而嵌套对象在其父对象不再可访问时是不可访问的。但我更深入地研究了这意味着什么,对这些东西如何工作的更深入的解释实际上对我很有启发。
  • @velis 好吧,直觉上这对我来说也很荒谬,因为如果这种行为确实存在,我将在我从事的所有项目中出现大量内存泄漏。但是,我链接到的关于可达性的 Oracle 文档让我更加困惑,并让我开始怀疑这个“显而易见的”事实。
  • 我明白了。我必须承认,我从未深入研究过 GC,以至于无法进一步解释它。我发现 JB Nizet、kjkrum 和 aquaraga 后来的 cmets 内容丰富且完整。我什至不确定这是一个更深一层的解释。 GC是一个简单的概念,否则实施起来成本太高。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-08
  • 1970-01-01
  • 2013-01-27
  • 2013-11-30
  • 2011-08-15
  • 2015-07-20
相关资源
最近更新 更多