che*_*rma 2 java memory-leaks concurrenthashmap
让我们说我们<k,v>从中删除一个条目ConcurrentHashMap.remove操作ConcurrentHashMap将克隆必须删除的节点之前的节点.
现在我的问题是Java垃圾如何收集必须删除的节点之前的原始节点.
让我们说1---> 2---> 3---> 4---> 5---> 6是一个由其维护的hashentry列表ConcurrentHashMap.现在我们要删除3.
以下代码是Java中remove方法的代码片段 ConcurrentHashMap
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;
}
Run Code Online (Sandbox Code Playgroud)
第一次迭代后
1---> 2---> 3---> 4---> 5--->6
1A---> 2A---> 4---> 5--->6
1A将创建一个指向的新节点4.原始节点3仍指向节点4.因此,节点4由2个节点指向
第二次迭代后
1---> 2---> 3---> 4---> 5--->6
1A---> 2A---> 4---> 5--->6
该节点4是一个指向两个列表的指针(1---> 2---> 3)和(1A---> 2A).Node 4(1---> 2---> 3)之前的原始节点永远不会从hashenlist列表中删除.
这不是内存泄漏的情况.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
Run Code Online (Sandbox Code Playgroud)
其次,这是一个单链表,所以迭代如下:
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 ----^
Run Code Online (Sandbox Code Playgroud)
(步骤0是初始状态,步骤1和2是循环的两次迭代,步骤3是tab[index] = newFirst)
正如您所看到的,在第3步之后没有任何指向1,因此它符合GC的条件,因此,2和3.
Ps:还要注意新列表中的顺序2A和1A反转顺序.除非碰撞太多,否则这应该没有实际影响,但在这种情况下,碰撞本身比这引入的微小时间不一致要大得多.