简体   繁体   English

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

[英]Memory Leakage during removal of an entry in concurrent hashmap

Lets say we remove an entry <k,v> from ConcurrentHashMap . 假设我们从ConcurrentHashMap删除条目<k,v> The remove operation in ConcurrentHashMap will clone the nodes preceding the node which has to be deleted. ConcurrentHashMap的remove操作将克隆必须删除的节点之前的节点。

Now My question is how Java garbage collect the original nodes preceding the nodes which has to be deleted. 现在,我的问题是Java如何垃圾收集必须删除的节点之前的原始节点。

Lets say 1 ---> 2 ---> 3 ---> 4 ---> 5 ---> 6 is a hashentry list which is maintained by ConcurrentHashMap . 可以说1 ---> 2 ---> 3 ---> 4 ---> 5 ---> 6是一个哈希表列表,由ConcurrentHashMap维护。 Now we want to remove 3 . 现在我们要删除3

The following code is the code snippet of the remove method in Java ConcurrentHashMap 以下代码是Java ConcurrentHashMap 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;
}
  • After 1st iteration 第一次迭代后

    1 ---> 2 ---> 3 ---> 4 ---> 5 ---> 6 1 > 2 ---> 3 ---> 4 ---> 5 ---> 6

    1A ---> 2A ---> 4 ---> 5 ---> 6 1A ---> 2A ---> 4 ---> 5 ---> 6

    A new node 1A will be created which will point to 4 . 将创建一个新节点1A ,它指向4 The Original Node 3 is still pointing to node 4 . 原始节点3仍指向节点4 Thus node 4 is pointed by 2 nodes 因此,节点4由2个节点指向

  • After 2nd Iteration 第二次迭代后

    1 ---> 2 ---> 3 ---> 4 ---> 5 ---> 6 1 > 2 ---> 3 ---> 4 ---> 5 ---> 6

    1A ---> 2A ---> 4 ---> 5 ---> 6 1A ---> 2A ---> 4 ---> 5 ---> 6

    The node 4 is a pointer to two list now ( 1 ---> 2 ---> 3 ) and ( 1A ---> 2A ). 节点4是现在指向两个列表的指针( 1 > 2 ---> 3 )和( 1A ---> 2A )。 The original nodes preceding Node 4 ( 1 ---> 2 ---> 3 ) are never removed from list of hashentries. 节点4之前的原始节点( 1 ---> 2 ---> 3 )永远不会从哈希表中删除。

Ain't this is the case of memory leakage. 这不是内存泄漏的情况。 How the GC will collect ( 1 ---> 2 ---> 3 ) as they are still being referenced by ConcurrentHashMap ? 由于ConcurrentHashMap仍在引用GC,GC将如何收集它们( 1 > 2 ---> 3 )?

I think you misread that code a bit. 我认为您有点误读了该代码。 First of all, the loop looks like this: 首先,循环如下所示:

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

Secondly, this is a singly-linked list, so the iteration goes like this: 其次,这是一个单链表,因此迭代过程如下:

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 ----^

(Step 0 is the initial state, steps 1 and 2 are the two iterations of the loop and step 3 is tab[index] = newFirst ) (步骤0是初始状态,步骤1和2是循环的两次迭代,步骤3是tab[index] = newFirst

As you can see, after step 3 there's nothing pointing to 1 , so it's eligible for GC and as a result, so are 2 and 3 . 如您所见,在第3步之后,没有任何东西指向1 ,因此它有资格使用GC,因此, 23

Ps: Also note how the order of 2A and 1A is reversed in the new list. 请注意在新列表中2A1A的顺序如何颠倒。 This should have no practical impact unless you have way too many collisions, but in that case the collisions themselves are a far bigger problem than the slight timing inconsistency this introduces. 除非您有太多的冲突,否则这不会产生实际影响,但是在那种情况下,冲突本身是一个更大的问题,而不是由此带来的轻微时序不一致。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM