为什么这段代码不能确保完成垃圾回收?

时间:2015-02-12 10:44:21

标签: java memory-management garbage-collection

previous answer forcing garbage collection上,@shamsjslibs提出此方法:

/**
 * This method guarantees that garbage collection is done unlike <code>{@link System#gc()}</code>
 */
public static void gc() {
    Object obj = new Object();
    WeakReference ref = new WeakReference<Object>(obj);
    obj = null;
    while (ref.get() != null) {
        System.gc();
    }
}

但在a comment中,@MarkoTopolnik不同意此方法保证垃圾收集完成这一事实。

我不明白为什么检查弱引用对象是否被证实不是证据?

4 个答案:

答案 0 :(得分:2)

The java command manual entry提供确凿证据System.gc()无法保证会导致垃圾回收。在&#34;高级垃圾收集选项&#34;部分,它描述了这个选项:

  

<强> -XX:+ DisableExplicitGC

     

启用禁用处理System.gc()调用的选项。默认情况下禁用此选项,这意味着将处理对System.gc()的调用。如果禁用了对System.gc()的调用的处理,则JVM在必要时仍会执行GC。

System.gc()的javadoc谈论&#34;尽力而为&#34;时,这可能意味着&#34;根本没有努力&#34;。


你说:

  

我不明白为什么检查弱引用对象是否被证实不是证据?

您的&#34;证明&#34;是基于一个谬论,最好的说明:

  

今天我画了我的信箱,我的小猫就死了。

     

我可以从逻辑上得出结论,每当我画信箱时,小猫都会死吗?

     

如果其他人描绘信箱,它是否也适用?或者如果我画前门?


还有另一个原因可能导致您的示例在不同的JVM上表现不同。

当您将null分配给obj时,方法范围的其余部分中的任何内容都不会读取该变量。因此,编译器允许来优化分配。正如JLS 17.4所说:

  

&#34;内存模型描述了程序的可能行为。一个实现可以自由地生成它喜欢的任何代码,只要程序的所有结果执行产生一个可以由内存模型预测的结果。&#34;

     

&#34;这为实现者提供了大量的自由来执行无数的代码转换,包括重新排序操作和删除不必要的同步。&#34;

如果分配被优化掉,那么GC可以看到变量中的先前非空值,处理对象仍然可以访问,并且不会破坏WeakReference

我不能告诉你是否有一个类似的Java实现,但我认为1)JLS允许这样做,2)它是JIT编译器执行的合理优化。

答案 1 :(得分:1)

如上所述,java垃圾收集不能强制...但它可以帮助。 如此好的java代码在它们完成时总是为null变量,因为归零变量的行为引起了垃圾收集器的兴趣。

类似的弱引用由垃圾收集器维护得比其他引用更紧密,这本质上是弱引用的目的。您必须记住,如果只有定义类本身具有对它的引用,则会收集弱引用。这意味着你不能使用弱引用来代替普通引用。

管理垃圾收集的技术是一个很大的主题,它在Java的实现之间有所不同。例如,Android java比Oracle java更积极地收集垃圾。

答案 2 :(得分:1)

  

我不明白为什么检查一个弱引用对象是否已被证实?

除了基于规范的其他人指出的原因之外,还有一个简单的问题,即您正在尝试测试完整GC 。在年轻一代的收藏中可能会剔除弱参考。

对于像G1这样的基于区域的GC,部分老一代的GC也是可能的。

对于完全并发的GC,如Azul的C4,“完整GC”的概念甚至可能不存在。

最重要的是,即使单个完整的GC传递可能也不是“完整的”,因为一旦某个对象被回收,可能会使用引用/终结器队列来懒惰地处理其他对象,即多个GC传递并且可能需要参考队列处理步骤,这取决于程序逻辑以释放所有内容。 在基于引用队列的本机资源处理的情况下,这可能非常重要。

答案 3 :(得分:0)

作为开发人员,您无法强制垃圾收集器运行,您可以做的就是请求它。 JVM将决定它是否运行。

你无能为力。