< prev index next >

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

Print this page

        

*** 27,37 **** import jdk.internal.vm.annotation.DontInline; import jdk.internal.HotSpotIntrinsicCandidate; import jdk.internal.misc.JavaLangRefAccess; import jdk.internal.misc.SharedSecrets; - import jdk.internal.ref.Cleaner; /** * 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 --- 27,36 ----
*** 105,132 **** /* When active: next element in a discovered reference list maintained by GC (or this if last) * pending: next element in the pending list (or null if last) * otherwise: NULL */ ! private transient Reference<T> discovered; /* used by VM */ /* Object used to synchronize with the garbage collector. The collector * must acquire this lock at the beginning of each collection cycle. It is * therefore critical that any code holding this lock complete as quickly * as possible, allocate no new objects, and avoid calling user code. */ private static class Lock { } ! private static Lock lock = new Lock(); /* List of References waiting to be enqueued. The collector adds * References to this list, while the Reference-handler thread removes * them. This list is protected by the above lock object. The * list uses the discovered field to link its elements. */ ! private static Reference<Object> pending = null; /* High-priority thread to enqueue pending References */ private static class ReferenceHandler extends Thread { --- 104,131 ---- /* When active: next element in a discovered reference list maintained by GC (or this if last) * pending: next element in the pending list (or null if last) * otherwise: NULL */ ! private transient Reference<?> discovered; /* used by VM */ /* Object used to synchronize with the garbage collector. The collector * must acquire this lock at the beginning of each collection cycle. It is * therefore critical that any code holding this lock complete as quickly * as possible, allocate no new objects, and avoid calling user code. */ private static class Lock { } ! private static final Lock lock = new Lock(); /* List of References waiting to be enqueued. The collector adds * References to this list, while the Reference-handler thread removes * them. This list is protected by the above lock object. The * list uses the discovered field to link its elements. */ ! private static Reference<?> pending; /* High-priority thread to enqueue pending References */ private static class ReferenceHandler extends Thread {
*** 137,225 **** 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, null, name, 0, false); } public void run() { while (true) { ! tryHandlePending(true); } } } /** ! * Try handle pending {@link Reference} if there is one.<p> ! * Return {@code true} as a hint that there might be another ! * {@link Reference} pending or {@code false} when there are no more pending ! * {@link Reference}s at the moment and the program can do some other ! * useful work instead of looping. ! * ! * @param waitForNotify if {@code true} and there was no pending ! * {@link Reference}, wait until notified from VM ! * or interrupted; if {@code false}, return immediately ! * when there is no pending {@link Reference}. ! * @return {@code true} if there was a {@link Reference} pending and it ! * was processed, or we waited for notification and either got it ! * or thread was interrupted before being notified; ! * {@code false} otherwise. ! */ ! static boolean tryHandlePending(boolean waitForNotify) { ! Reference<Object> r; ! 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. ! if (waitForNotify) { lock.wait(); - } - // retry if waited - return waitForNotify; - } - } } 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 - return true; } catch (InterruptedException x) { ! // retry ! return true; } ! ! // Fast path for cleaners ! if (c != null) { ! c.clean(); ! return true; } ! ReferenceQueue<? super Object> q = r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); ! return true; } static { ThreadGroup tg = Thread.currentThread().getThreadGroup(); for (ThreadGroup tgn = tg; --- 136,205 ---- throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e); } } static { ! // pre-load and initialize InterruptedException class // so that we don't get into trouble later in the run loop if there's ! // memory shortage while loading/initializing it lazily. ensureClassInitialized(InterruptedException.class); } ReferenceHandler(ThreadGroup g, String name) { super(g, null, name, 0, false); } public void run() { while (true) { ! Reference<?> p = getPendingReferences(); ! enqueuePendingReferences(p); } } } /** ! * Blocks until GC discovers some pending references and hands them to us. ! * ! * @return a list of pending references linked via {@link #discovered} field ! * with {@code null} marking the end of list. ! */ ! static Reference<?> getPendingReferences() { ! Reference<?> p; synchronized (lock) { ! while ((p = pending) == null) { ! try { lock.wait(); } catch (OutOfMemoryError x) { ! // The waiting on the lock may cause an OutOfMemoryError ! // because it may try to allocate InterruptedException object. ! // Give other threads CPU time so they hopefully drop some live ! // references and GC reclaims some space. Thread.yield(); } catch (InterruptedException x) { ! // ignore interrupts } ! } ! pending = null; ! } ! return p; } ! /** ! * Enqueue a list of pending {@link Reference}s. ! * ! * @param p a list of pending references linked via {@link #discovered} ! * field with {@code null} marking the end of list ! */ ! static void enqueuePendingReferences(Reference<?> p) { ! while (p != null) { ! Reference<?> r = p; ! p = r.discovered; ! r.discovered = null; ! @SuppressWarnings("unchecked") ! ReferenceQueue<Object> q = (ReferenceQueue) r.queue; if (q != ReferenceQueue.NULL) q.enqueue(r); ! } } static { ThreadGroup tg = Thread.currentThread().getThreadGroup(); for (ThreadGroup tgn = tg;
*** 233,245 **** handler.setDaemon(true); handler.start(); // provide access in SharedSecrets SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() { @Override ! public boolean tryHandlePendingReference() { ! return tryHandlePending(false); } }); } /* -- Referent accessor and setters -- */ --- 213,226 ---- handler.setDaemon(true); handler.start(); // provide access in SharedSecrets SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() { + @Override ! public boolean cleanNextEnqueuedCleanable(Cleaner cleaner) { ! return cleaner.cleanNextEnqueued(); } }); } /* -- Referent accessor and setters -- */
< prev index next >