# HG changeset patch # User coffeys # Date 1391092695 0 # Node ID dcd0c84f4b06c76416e37c56dd9b25ca68c9f291 # Parent 2b4c9efdf2d719d7dc7906a37efa61c15d197ea3# Parent e929c13f8d11657b01c9659cfb8fe64179aaa7a0 Merge diff -r 2b4c9efdf2d7 -r dcd0c84f4b06 jdk/src/share/classes/java/lang/ref/Reference.java --- a/jdk/src/share/classes/java/lang/ref/Reference.java Thu Jan 30 12:22:24 2014 +0400 +++ b/jdk/src/share/classes/java/lang/ref/Reference.java Thu Jan 30 14:38:15 2014 +0000 @@ -111,7 +111,7 @@ * therefore critical that any code holding this lock complete as quickly * as possible, allocate no new objects, and avoid calling user code. */ - static private class Lock { }; + static private class Lock { } private static Lock lock = new Lock(); @@ -126,6 +126,22 @@ */ private static class ReferenceHandler extends Thread { + private static void ensureClassInitialized(Class clazz) { + try { + Class.forName(clazz.getName(), true, clazz.getClassLoader()); + } catch (ClassNotFoundException e) { + throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e); + } + } + + static { + // pre-load and initialize InterruptedException and Cleaner classes + // so that we don't get into trouble later in the run loop if there's + // memory shortage while loading/initializing them lazily. + ensureClassInitialized(InterruptedException.class); + ensureClassInitialized(Cleaner.class); + } + ReferenceHandler(ThreadGroup g, String name) { super(g, name); } @@ -133,37 +149,40 @@ public void run() { for (;;) { Reference r; - synchronized (lock) { - if (pending != null) { - r = pending; - pending = r.discovered; - r.discovered = null; - } else { - // The waiting on the lock may cause an OOME because it may try to allocate - // exception objects, so also catch OOME here to avoid silent exit of the - // reference handler thread. - // - // Explicitly define the order of the two exceptions we catch here - // when waiting for the lock. - // - // We do not want to try to potentially load the InterruptedException class - // (which would be done if this was its first use, and InterruptedException - // were checked first) in this situation. - // - // This may lead to the VM not ever trying to load the InterruptedException - // class again. - try { - try { - lock.wait(); - } catch (OutOfMemoryError x) { } - } catch (InterruptedException x) { } - continue; + Cleaner c; + try { + synchronized (lock) { + if (pending != null) { + r = pending; + // 'instanceof' might throw OutOfMemoryError sometimes + // so do this before un-linking 'r' from the 'pending' chain... + c = r instanceof Cleaner ? (Cleaner) r : null; + // unlink 'r' from 'pending' chain + pending = r.discovered; + r.discovered = null; + } else { + // The waiting on the lock may cause an OutOfMemoryError + // because it may try to allocate exception objects. + lock.wait(); + continue; + } } + } catch (OutOfMemoryError x) { + // Give other threads CPU time so they hopefully drop some live references + // and GC reclaims some space. + // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above + // persistently throws OOME for some time... + Thread.yield(); + // retry + continue; + } catch (InterruptedException x) { + // retry + continue; } // Fast path for cleaners - if (r instanceof Cleaner) { - ((Cleaner)r).clean(); + if (c != null) { + c.clean(); continue; }