Fix memory leak in ConcurrentReferenceHashMap
Update ConcurrentReferenceHashMap to protect against references that have been garbage collected but for some reason do not appear as a `pollForPurge` result. Also added purgeUnreferencedEntries() method to allow for programmatic cleanup. Issue: SPR-11440
This commit is contained in:
parent
fe6a9826c5
commit
2b4c81e642
|
@ -338,6 +338,19 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove any entries that have been garbage collected and are no longer referenced.
|
||||||
|
* Under normal circumstances garbage collected entries are automatically purged as
|
||||||
|
* items are added or removed from the Map. This method can be used to force a purge,
|
||||||
|
* and is useful when the Map is read frequently but updated less often.
|
||||||
|
*/
|
||||||
|
public void purgeUnreferencedEntries() {
|
||||||
|
for (Segment segment : this.segments) {
|
||||||
|
segment.restructureIfNecessary(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int size() {
|
public int size() {
|
||||||
int size = 0;
|
int size = 0;
|
||||||
|
@ -512,7 +525,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
|
||||||
* references that have been garbage collected.
|
* references that have been garbage collected.
|
||||||
* @param allowResize if resizing is permitted
|
* @param allowResize if resizing is permitted
|
||||||
*/
|
*/
|
||||||
private void restructureIfNecessary(boolean allowResize) {
|
protected final void restructureIfNecessary(boolean allowResize) {
|
||||||
boolean needsResize = ((this.count > 0) && (this.count >= this.resizeThreshold));
|
boolean needsResize = ((this.count > 0) && (this.count >= this.resizeThreshold));
|
||||||
Reference<K, V> reference = this.referenceManager.pollForPurge();
|
Reference<K, V> reference = this.referenceManager.pollForPurge();
|
||||||
if ((reference != null) || (needsResize && allowResize)) {
|
if ((reference != null) || (needsResize && allowResize)) {
|
||||||
|
@ -550,7 +563,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
|
||||||
restructured[i] = null;
|
restructured[i] = null;
|
||||||
}
|
}
|
||||||
while (reference != null) {
|
while (reference != null) {
|
||||||
if (!toPurge.contains(reference)) {
|
if (!toPurge.contains(reference) && (reference.get() != null)) {
|
||||||
int index = getIndex(reference.getHash(), restructured);
|
int index = getIndex(reference.getHash(), restructured);
|
||||||
restructured[index] = this.referenceManager.createReference(
|
restructured[index] = this.referenceManager.createReference(
|
||||||
reference.get(), reference.getHash(),
|
reference.get(), reference.getHash(),
|
||||||
|
@ -564,7 +577,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
|
||||||
if (resizing) {
|
if (resizing) {
|
||||||
setReferences(restructured);
|
setReferences(restructured);
|
||||||
}
|
}
|
||||||
this.count = countAfterRestructure;
|
this.count = Math.max(countAfterRestructure, 0);
|
||||||
} finally {
|
} finally {
|
||||||
unlock();
|
unlock();
|
||||||
}
|
}
|
||||||
|
@ -974,6 +987,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
|
||||||
enqueue();
|
enqueue();
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1007,6 +1021,7 @@ public class ConcurrentReferenceHashMap<K, V> extends AbstractMap<K, V> implemen
|
||||||
enqueue();
|
enqueue();
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue