GC如何在范围中部工作



我的代码如下:

public void foo()
{
    Object x = new LongObject();
    doSomething(x);
    //More Code
    // x is never used again
    // x = null helps GB??
    Object x2 = new LongObject();
    doSomething(x2);
}

如果需要,我希望X仿生的内存可以由GC免费。但是我不知道设置为null是必要的还是编译器。

实际上,JIT对参考文献进行了livesice分析(在字节码级别在当前帧中存储为插槽)。如果再也不会阅读参考,则可以重复使用其插槽,而JIT将知道这一点。只要编译器和JIT能够证明该变量将永远不会被删除,就可以完全可以收集物体收集垃圾。

重点是: scope language 的构造,并指定像 x之类的名称在其发生的程序代码文本中的任何时刻含义。 lifetime 是对象的属性,JIT和GC通常以非明显的方式进行管理。

请记住,JIT可以在运行时重新编译您的代码,并在执行时会优化代码。除非您确实肯定您知道自己在做什么,否则不要尝试超越JIT。编写正确的代码,然后让JIT完成工作,只有在您有证据表明JIT做得不够好时才担心。

要从字面上回答您的问题,编译器(将源代码转到字节码编译器)永远不会插入null分配,但是仍然,将变量分配给null是不必要的 - 通常通常/em>。

正如该答案所解释的那样,范围是一件编译时的事情,正式地,如果无法"从任何实时线程中访问任何潜在的持续计算中",则有资格获得垃圾收集的条件。但是,不能保证特定实现将确定哪些合格对象。正如链接的答案还解释的那样,JIT编译的代码只会保留对随后将访问的对象的引用。这可能比您预期的更进一步,允许垃圾收集看起来像在源代码中使用的对象,因为运行时优化可能会转换代码并减少实际内存访问。

但是,在解释模式下,分析不会走那么远,并且在当前堆栈框架中可能有对象引用,以阻止参考物的收集,尽管该变量之后没有在源代码中使用,甚至不在范围内使用。。不能保证在执行该方法时从解释到编译的代码转换能够摆脱这种悬而未决的参考。当实际重型计算发生在doSomething中时,热点优化器甚至不太可能考虑编译foo()

仍然,这很少是一个问题。运行解释仅发生在初始化或第一次执行期间,即使这些对象很大,如果将这样的对象收集得比它的收集得比,也很少有问题。平均应用程序由数百万对象组成。

但是,如果您认为可能存在问题,则可以轻松解决此问题,而无需将null分配给变量。限制范围:

public void foo()
{
    {
        Object x = new LongObject();
        doSomething(x);
        //More Code
    }
    {
        Object x2 = new LongObject();
        doSomething(x2);
    }
}

除了分配null(将变量范围限制为实际使用范围)外,即使在对编译代码没有影响的情况下,也可以改善源代码质量。虽然范围纯粹是源代码的东西,但它可能会对字节码产生影响。在上面的代码中,编译器将重复使用x在堆栈框架中存储x2的位置,因此在第二个doSomething执行期间不存在第一个LongObject的引用。

如所述,这对于内存管理和提高源代码质量不需要做出决定,而不是尝试帮助垃圾收集器。

最新更新