src/share/classes/java/lang/ref/Reference.java

Print this page

        

*** 24,33 **** --- 24,34 ---- */ package java.lang.ref; import sun.misc.Cleaner; + import sun.misc.Unsafe; /** * Abstract base class for reference objects. This class defines the * operations common to all reference objects. Because reference objects are * implemented in close cooperation with the garbage collector, this class may
*** 124,171 **** /* High-priority thread to enqueue pending References */ private static class ReferenceHandler extends Thread { ReferenceHandler(ThreadGroup g, String name) { super(g, name); } public void run() { for (;;) { Reference<Object> 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; } } // Fast path for cleaners ! if (r instanceof Cleaner) { ! ((Cleaner)r).clean(); continue; } ReferenceQueue<Object> q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); --- 125,185 ---- /* High-priority thread to enqueue pending References */ private static class ReferenceHandler extends Thread { + 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. + Unsafe unsafe = Unsafe.getUnsafe(); + unsafe.ensureClassInitialized(InterruptedException.class); + unsafe.ensureClassInitialized(Cleaner.class); + } + ReferenceHandler(ThreadGroup g, String name) { super(g, name); } public void run() { for (;;) { Reference<Object> r; + Cleaner c; + try { synchronized (lock) { r = pending; + if (r != null) { + // 'instanceof' might throw OOME sometimes so do this before + // unlinking '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 OOME because it may try to allocate ! // exception objects. lock.wait(); continue; } } + } catch (OutOfMemoryError x) { + // Catch OOME from 'r instanceof Cleaner' or 'lock.wait()'. + // 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) { + // Catch InterruptedException from 'lock.wait()' and retry + continue; + } // Fast path for cleaners ! if (c != null) { ! c.clean(); continue; } ReferenceQueue<Object> q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r);