Tony.S 2009-06-06 10:23
浏览 266
已采纳

[JVM]请问a = null,对于垃圾回收,有效果吗

[JVM]请问a = null,对于垃圾回收,有效果吗

如A a = new A();
.........
最后用完了 a=  null;

  • 写回答

6条回答 默认 最新

  • rednaxelafx 2009-06-07 16:37
    关注

    随便说个,随便听听……
    各个JVM的实现方式不同,设null有没有影响也是不一定的。也就是说如果想确定一用完某个对象马上就释放其占用的内存空间,没有在各JVM上都通用的办法。

    于是就可以看些有趣的例子了。许多JVM的实现都会在合适的时候把字节码即时编译为机器码,在这过程中有可能做方法内联、无用代码消除等诸多优化。看这个假象例子:
    [code="java"]public class Foo {
    public void bar() {
    A a = new A();
    a.doTask(this);
    }
    }

    public class Quux {
    public void baz() {
    Foo foo = getFoo();
    for (int i = 0; i < 100000; i++) {
    foo.bar();
    }
    doSomeLongTask();
    }

    private void doSomeLongTask() {
        // ...
    }
    

    }[/code]
    Foo.bar()是一个小方法,而且在一个高强度的循环里被调用,则如果Quux.bar()被多调用几次,在某些JVM上就有机会看到实际运行的Quux.baz()代码变成了类似这样:
    [code="java"]public void baz() {
    Foo foo = getFoo();
    if (Foo.class == foo.getClass()) { // guarded inline method cache
    for (int i = 0; i < 100000; i++) {
    A a = new A();
    a.doTask(foo);
    }
    } else {
    for (int i = 0; i < 100000; i++) {
    foo.bar(); // fallback
    }
    }
    doSomeLongTask();
    }[/code]
    甚至有可能进一步把A.doTask()也内联进来。
    这样,a这个引用的作用域就跑到Quux.baz()里了。

    如果原先在Foo.bar()里写上了a = null;会怎样呢?
    1、这句有可能原本就被优化掉了(因为这是对变量的赋值,而赋值后没有代码再读取过这个值)。反正方法调用结束后局部变量自然消失,设不设null都一样 << 前提是没内联优化。
    2、这句没有一开始就被优化掉,而是被内联来到了Quux.baz()里:
    [code="java"]public void baz() {
    Foo foo = getFoo();
    if (Foo.class == foo.getClass()) { // guarded inline method cache
    for (int i = 0; i < 100000; i++) {
    A a = new A();
    a.doTask(foo);
    a = null;
    }
    } else {
    for (int i = 0; i < 100000; i++) {
    foo.bar(); // fallback
    }
    }
    doSomeLongTask();
    }[/code]
    看起来似乎很有用对吧?似乎在Quux.baz()的中间就把a设为了null,减少了一个对new A()得到的对象的引用?
    如果JVM有能力把代码内联进来,也就不差在计算变量的存活范围和消除无用代码了。于是a = null;照样被当作无用代码消除掉,同时也可以得知a变量的存货范围只有for循环里的两行,所以Quux.baz()的其它局部变量可以在其它时间占用a所在的寄存器或栈空间。设不设null还是一样。如果在执行doSomeLongTask()时进行GC,即时不设置a为null,GC也会认为没有那个引用,不影响可能的回收。

    但如果没那么多优化,JVM就老老实实的执行没优化过的字节码呢?
    [code="java"]public void baz() {
    Foo foo = getFoo();
    A a = new A();
    a.doTask(foo);
    a = null;
    doSomeLongTask();
    }[/code]
    JVM可能会老老实实把全部局部变量都放在栈帧上,可能不消除无用代码,可能在doSomeLongTask()的执行过程中进行了GC。如果a没有被手工设为null,则GC的时候会看到栈上还存在一个指向new A()得到的对象的引用,于是认为该对象还是活的。

    手工设置null最有用的场景恐怕就是在特定JVM上配合System.gc()来用了吧 =v=

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(5条)

报告相同问题?