# HG changeset patch # User hannesw # Date 1379671868 -7200 # Node ID 932f6ab73e6797f413a61231ceb0c9083a167d81 # Parent 984244201382f25d7542017524385ee5ceef96d2 8022587: ClassCache is not optimal and leaks Source instances Reviewed-by: lagergren, attila diff -r 984244201382 -r 932f6ab73e67 nashorn/src/jdk/nashorn/internal/objects/Global.java --- a/nashorn/src/jdk/nashorn/internal/objects/Global.java Fri Sep 20 12:56:07 2013 +0530 +++ b/nashorn/src/jdk/nashorn/internal/objects/Global.java Fri Sep 20 12:11:08 2013 +0200 @@ -33,6 +33,7 @@ import java.io.PrintWriter; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; +import java.lang.ref.ReferenceQueue; import java.lang.ref.SoftReference; import java.lang.reflect.Field; import java.util.Arrays; @@ -691,17 +692,41 @@ * Cache for compiled script classes. */ @SuppressWarnings("serial") - private static class ClassCache extends LinkedHashMap>> { + private static class ClassCache extends LinkedHashMap { private final int size; + private final ReferenceQueue> queue; ClassCache(int size) { super(size, 0.75f, true); this.size = size; + this.queue = new ReferenceQueue<>(); + } + + void cache(final Source source, final Class clazz) { + put(source, new ClassReference(clazz, queue, source)); + } + + @Override + protected boolean removeEldestEntry(final Map.Entry eldest) { + return size() > size; } @Override - protected boolean removeEldestEntry(final Map.Entry>> eldest) { - return size() >= size; + public ClassReference get(Object key) { + for (ClassReference ref; (ref = (ClassReference)queue.poll()) != null; ) { + remove(ref.source); + } + return super.get(key); + } + + } + + private static class ClassReference extends SoftReference> { + private final Source source; + + ClassReference(final Class clazz, final ReferenceQueue> queue, final Source source) { + super(clazz, queue); + this.source = source; } } @@ -709,22 +734,14 @@ @Override public Class findCachedClass(final Source source) { assert classCache != null : "Class cache used without being initialized"; - SoftReference> ref = classCache.get(source); - if (ref != null) { - final Class clazz = ref.get(); - if (clazz == null) { - classCache.remove(source); - } - return clazz; - } - - return null; + ClassReference ref = classCache.get(source); + return ref != null ? ref.get() : null; } @Override public void cacheClass(final Source source, final Class clazz) { assert classCache != null : "Class cache used without being initialized"; - classCache.put(source, new SoftReference>(clazz)); + classCache.cache(source, clazz); } private static T getLazilyCreatedValue(final Object key, final Callable creator, final Map map) {