为什么此代码不能确保已完成完整的垃圾收集?

Why this code does not ensure that a full garbage collection has been done?

previous answer on forcing garbage collection, @shams proposes this method from jslibs:

/**
 * 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 中不同意此方法 保证完成垃圾收集的事实

我不明白为什么检查弱引用对象是否已被垃圾化不是证明?

作为开发人员,您不能强迫垃圾收集器 运行,您所能做的就是请求它。 JVM 将决定它是否 运行s.

对此你无能为力。

如上所述,java 垃圾收集不能强制...但可以帮助。 这么好的 java 代码在完成时总是将变量设为 null,因为将变量设为 null 的行为会引起垃圾收集器的兴趣。

同样弱引用比其他引用更容易被垃圾收集器维护,这本质上就是弱引用的目的。你必须记住,如果只有定义 class 本身有对它的引用,就会收集弱引用。这意味着您不能使用弱引用来替代普通引用。

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

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

-XX:+DisableExplicitGC

Enables the option that disables processing of calls to System.gc(). This option is disabled by default, meaning that calls to System.gc() are processed. If processing of calls to System.gc() is disabled, the JVM still performs GC when necessary.

System.gc() 的 javadoc 谈到“尽力而为”时,这可能意味着“完全不努力”。


你说:

I don't understand why checking if a weak referenced object have been garbaged is not a proof ?

你的“证明”是基于一个谬论,最好的说明是:

Today I painted my letterbox and my kitten died.

Can I logically conclude that every time I paint my letterbox, a kitten will die?

Does it also apply if someone else paints a letterbox? Or if I paint my front gate?


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

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

"The memory model describes possible behaviors of a program. An implementation is free to produce any code it likes, as long as all resulting executions of a program produce a result that can be predicted by the memory model."

"This provides a great deal of freedom for the implementor to perform a myriad of code transformations, including the reordering of actions and removal of unnecessary synchronization."

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

我无法告诉您是否有一个 Java 实现会表现得像那样,但我认为 1) JLS 允许这样做,以及 2) 它是 JIT 编译器的合理优化执行。

I don't understand why checking if a weak referenced object have been garbaged is not a proof ?

除了其他人根据规范指出的原因之外,还有一个简单的问题,即您正在尝试测试 full GC。弱引用可能会在新生代收集过程中被剔除。

使用基于区域的 GC,例如 G1 部分老年代 GC 也是可能的。

并且对于像 Azul 的 C4 这样的完全并发的 GC,"full GC" 的概念甚至可能不存在。

最重要的是,即使是一次完整的 GC 传递也可能不是 "complete",因为 reference/finalizer 队列可能用于在某些对象被回收后延迟处理其他对象,即根据程序逻辑释放所有内容,可能需要多次 GC 传递和引用队列处理步骤。 这在基于引用队列的本机资源处理的情况下非常重要。