GC如何在范围中间工作

时间:2017-12-05 11:19:28

标签: java garbage-collection

我的代码如下:

<canvas id="myCanvas" height="300" width="450" style="border: 1px solid black"></canvas>

如果需要,我希望由x分配的内存可以由GC免费提供。但我不知道是否需要设置为null或编译器。

2 个答案:

答案 0 :(得分:1)

事实上,JIT对引用进行了活跃度分析(在字节码级别将其存储为当前帧中的槽)。如果永远不再读取引用,则可以重用其槽,并且JIT将知道这一点。一个对象完全有可能被垃圾收集,而引用它的变量仍然在词法范围内,只要编译器和JIT能够证明该变量永远不会被解除引用。

重点是:范围语言的构造,并指定x之类的名称在程序文本的任何位置的含义它发生的代码。 Lifetime 是对象的属性,JIT和GC通常以非显而易见的方式管理它。

请记住,JIT可以在代码运行时重新编译代码,并在代码执行时发生的情况下优化代码。除非你确实确定你知道自己在做什么,否则不要试图超越JIT。编写正确的代码并让JIT完成它的工作,只有在你有证据表明JIT没有完成其工作时才会担心它。

答案 1 :(得分:0)

为了回答你的问题,编译器(说到字节码编译器的源代码)从不插入null赋值,但仍然没有必要将变量赋给null - 通常< / em>的

正如this answer所解释的那样,范围是一个编译时间,正式地说,如果一个对象不能“be accessed in any potential continuing computation from any live thread”,它就有资格进行垃圾收集。但是对于特定实现将识别哪个符合条件的对象没有保证。正如链接的答案也解释的那样,JIT编译的代码只会保留对随后访问的对象的引用。这可能比你期望的更进一步,允许垃圾收集看起来像在源代码中使用的对象,因为运行时优化可能会转换代码并减少实际的内存访问。

但是在解释模式下,分析不会到目前为止,并且在当前堆栈帧中可能存在对象引用,阻止了引用的收集,尽管之后未使用变量或甚至超出源代码中的范围。没有保证在执行方法时从解释代码切换到编译代码能够摆脱这种悬空引用。当实际繁重的计算发生在foo()内时,热点优化器甚至不太可能考虑编译doSomething

不过,这很少是一个问题。运行解释仅在初始化或第一次执行期间发生,即使这些对象很大,如果这样的对象稍晚收集也很少会出现问题。平均应用程序包含数百万个对象。

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

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

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

如上所述,内存管理很少需要这样做,提高源代码质量应该是推动决策,而不是尝试帮助垃圾收集器。