java.util.concurrent.LinkedBlockingQueue中的奇怪代码

Ale*_*nov 11 java puzzle garbage-collection java.util.concurrent

所有!

我在LinkedBlockingQueue中发现了奇怪的代码:

private E dequeue() {
        // assert takeLock.isHeldByCurrentThread();
        Node<E> h = head;
        Node<E> first = h.next;
        h.next = h; // help GC
        head = first;
        E x = first.item;
        first.item = null;
        return x;
}
Run Code Online (Sandbox Code Playgroud)

谁能解释为什么我们需要局部变量h?它对GC有什么帮助?

Mat*_*att 6

如果你看一下jsr166 src那么你会发现有问题的提交

http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/main/java/util/concurrent/LinkedBlockingQueue.java?view=log (见v 1.51)

这表明答案在这个错误报告中

http://bugs.sun.com/view_bug.do?bug_id=6805775

完整的讨论在这个主题中

http://thread.gmane.org/gmane.comp.java.jsr.166-concurrency/5758

"帮助GC"一点是为了避免事情流失到终身.

干杯

马特


Voo*_*Voo 5

也许有点晚了,但目前的解释对我来说完全不令人满意,我想我有一个更合理的解释。

首先,每个 java GC 都以某种方式从根集进行某种跟踪。这意味着如果旧的 head 被收集,我们next无论如何都不会读取变量 - 没有理由这样做。因此,在下一次迭代中收集IF头并不重要。

上句中的 IF 是这里的重要部分。在不同的东西旁边设置之间的区别对于收集头本身并不重要,但可能会对其他对象产生影响。

让我们假设一个简单的分代 GC:如果 head 在年轻集合中,无论如何它将在下一个 GC 中被收集。但是如果它在旧集合中,它只会在我们进行很少发生的完整 GC 时被收集。

那么如果 head 在旧集合中并且我们执行年轻 GC 会发生什么?在这种情况下,JVM 假定旧堆中的每个对象都还活着,并将从旧对象到新对象的每个引用添加到新 GC 的根集。这正是赋值在这里避免的:写入旧堆通常受到写屏障或其他东西的保护,以便 JVM 可以捕获此类赋值并正确处理它们 - 在我们的例子中,它next从根集中删除指向的对象确实有后果。

简短示例:

假设我们有1 (old) -> 2 (young) -> 3 (xx)。如果我们现在从列表中删除 1 和 2,我们可能期望这两个元素都将被下一次 GC 收集。但是如果只发生了一个年轻的 GC 并且我们没有删除next旧的指针,那么元素 1 和 2 都不会被收集。与此相反,如果我们删除了 1 中的指针,则 2 将被年轻 GC 收集。


Tud*_*dor 0

为了更好地理解发生的情况,让我们看看执行代码后列表的样子。首先考虑一个初始列表:

1 -> 2 -> 3
Run Code Online (Sandbox Code Playgroud)

然后h指向headfirstto h.next

1 -> 2 -> 3
|    |
h    first
Run Code Online (Sandbox Code Playgroud)

然后h.next指向hhead指向first

1 -> 2 -> 3
|   / \
h head first
Run Code Online (Sandbox Code Playgroud)

现在,实际上我们知道只有一个活动引用指向第一个元素,它本身就是 ( h.next = h),而且我们还知道 GC 会收集没有更多活动引用的对象,因此当方法结束时,(旧的)列表的头部可以被 GC 安全地收集,因为h它只存在于该方法的范围内。

话虽如此,有人指出,并且我同意这一点,即使使用经典的出队方法(即仅指向firsthead.next指向headfirst,也不再有指向旧头的引用。然而,在这种情况下,旧的头在内存中悬空,并且其next字段仍然指向first,而在您发布的代码中,唯一剩下的就是一个指向自身的孤立对象。这可能会触发 GC 更快地采取行动。

  • 为什么引用可达对象会困扰 GC? (2认同)