删除并发哈希图中的条目期间发生内存泄漏

Memory Leakage during removal of an entry in concurrent hashmap

假设我们从 ConcurrentHashMap 中删除了条目 <k,v>ConcurrentHashMap 中的删除操作将克隆必须删除的节点之前的节点。

现在我的问题是Java如何对必须删除的节点之前的原始节点进行垃圾回收。

假设 1--->2--->3--->4--->5-- ->6 是由 ConcurrentHashMap 维护的哈希列表。现在我们要删除 3.

以下代码是JavaConcurrentHashMap

中remove方法的代码片段
HashEntry newFirst = e.next;
for (HashEntry p = first; p != e; p = p.next) {
    newFirst = new HashEntry(p.key, p.hash, newFirst, p.value);
    tab[index]= newFirst;
}

这不就是内存泄漏吗。 GC 将如何收集 (1--->2--->3),因为它们仍被 ConcurrentHashMap 引用?

我认为您有点误读了该代码。首先,循环看起来像这样:

HashEntry newFirst = e.next; // the element after the deleted one, in our case: 4
for (HashEntry p = first; p != e; p = p.next) {
    newFirst = new HashEntry(p.key, p.hash, newFirst, p.value);
}
tab[index]= newFirst; // this is outside the loop

其次,这是一个单链表,所以迭代是这样的:

Step 0: tab[index] --> 1 --> 2 --> 3 --> 4 --> 5 --> 6
          newFirst ----------------------^
Step 1: tab[index] --> 1 --> 2 --> 3 --> 4 --> 5 --> 6
          newFirst --------------> 1A ---^
Step 2: tab[index] --> 1 --> 2 --> 3 --> 4 --> 5 --> 6
          newFirst -------> 2A --> 1A ---^
Step 3: tab[index] --> 2A--> 1A--> 4 --> 5 --> 6
                 1 --> 2 --> 3 ----^

(第0步为初始状态,第1、2步为循环的两次迭代,第3步为tab[index] = newFirst)

如您所见,在第 3 步之后没有任何内容指向 1,因此它符合 GC 的条件,因此 2 和 [=15= 也是如此].

P.s.: 还要注意 2A1A 的顺序在新列表中是如何颠倒的。这应该没有实际影响,除非你有太多的碰撞,但在那种情况下,碰撞本身比它引入的轻微时间不一致问题要大得多。