LUCENE-4459: Improve WeakIdentityMap.keyIterator() to remove GCed keys from backing map early instead of waiting for reap(). This makes test failures in TestWeakIdentityMap disappear, too.

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1394291 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Uwe Schindler 2012-10-04 21:58:26 +00:00
parent 5e144ab7bb
commit 532f82806f
3 changed files with 32 additions and 20 deletions

View File

@ -43,6 +43,11 @@ Optimizations
into the skipdata. You need to reindex any indexes created with into the skipdata. You need to reindex any indexes created with
this experimental codec. (Robert Muir) this experimental codec. (Robert Muir)
* LUCENE-4459: Improve WeakIdentityMap.keyIterator() to remove GCed keys
from backing map early instead of waiting for reap(). This makes test
failures in TestWeakIdentityMap disappear, too.
(Uwe Schindler, Mike McCandless, Robert Muir)
Build Build
* LUCENE-4451: Memory leak per unique thread caused by * LUCENE-4451: Memory leak per unique thread caused by

View File

@ -133,22 +133,22 @@ public final class WeakIdentityMap<K,V> {
@Override @Override
public boolean hasNext() { public boolean hasNext() {
return nextIsSet ? true : setNext(); return nextIsSet || setNext();
} }
@Override @SuppressWarnings("unchecked") @Override @SuppressWarnings("unchecked")
public K next() { public K next() {
if (nextIsSet || setNext()) { if (!hasNext()) {
try { throw new NoSuchElementException();
assert nextIsSet; }
return (K) next; assert nextIsSet;
} finally { try {
// release strong reference and invalidate current value: return (K) next;
nextIsSet = false; } finally {
next = null; // release strong reference and invalidate current value:
} nextIsSet = false;
next = null;
} }
throw new NoSuchElementException();
} }
@Override @Override
@ -161,14 +161,15 @@ public final class WeakIdentityMap<K,V> {
while (iterator.hasNext()) { while (iterator.hasNext()) {
next = iterator.next().get(); next = iterator.next().get();
if (next == null) { if (next == null) {
// already garbage collected! // the key was already GCed, we can remove it from backing map:
continue; iterator.remove();
} else {
// unfold "null" special value:
if (next == NULL) {
next = null;
}
return nextIsSet = true;
} }
// unfold "null" special value
if (next == NULL) {
next = null;
}
return nextIsSet = true;
} }
return false; return false;
} }

View File

@ -122,13 +122,16 @@ public class TestWeakIdentityMap extends LuceneTestCase {
for (int i = 0; size > 0 && i < 10; i++) try { for (int i = 0; size > 0 && i < 10; i++) try {
System.runFinalization(); System.runFinalization();
System.gc(); System.gc();
int newSize = map.size();
assertTrue("previousSize("+size+")>=newSize("+newSize+")", size >= newSize);
size = newSize;
Thread.sleep(100L); Thread.sleep(100L);
c = 0; c = 0;
for (Iterator<String> it = map.keyIterator(); it.hasNext();) { for (Iterator<String> it = map.keyIterator(); it.hasNext();) {
assertNotNull(it.next()); assertNotNull(it.next());
c++; c++;
} }
final int newSize = map.size(); newSize = map.size();
assertTrue("previousSize("+size+")>=iteratorSize("+c+")", size >= c); assertTrue("previousSize("+size+")>=iteratorSize("+c+")", size >= c);
assertTrue("iteratorSize("+c+")>=newSize("+newSize+")", c >= newSize); assertTrue("iteratorSize("+c+")>=newSize("+newSize+")", c >= newSize);
size = newSize; size = newSize;
@ -223,13 +226,16 @@ public class TestWeakIdentityMap extends LuceneTestCase {
for (int i = 0; size > 0 && i < 10; i++) try { for (int i = 0; size > 0 && i < 10; i++) try {
System.runFinalization(); System.runFinalization();
System.gc(); System.gc();
int newSize = map.size();
assertTrue("previousSize("+size+")>=newSize("+newSize+")", size >= newSize);
size = newSize;
Thread.sleep(100L); Thread.sleep(100L);
int c = 0; int c = 0;
for (Iterator<Object> it = map.keyIterator(); it.hasNext();) { for (Iterator<Object> it = map.keyIterator(); it.hasNext();) {
assertNotNull(it.next()); assertNotNull(it.next());
c++; c++;
} }
final int newSize = map.size(); newSize = map.size();
assertTrue("previousSize("+size+")>=iteratorSize("+c+")", size >= c); assertTrue("previousSize("+size+")>=iteratorSize("+c+")", size >= c);
assertTrue("iteratorSize("+c+")>=newSize("+newSize+")", c >= newSize); assertTrue("iteratorSize("+c+")>=newSize("+newSize+")", c >= newSize);
size = newSize; size = newSize;