< prev index next >
src/java.base/share/classes/java/lang/ref/Reference.java
Print this page
@@ -108,26 +108,16 @@
* 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.
+ /* Blocks until the reference pending list becomes non-empty and
+ * returns the list.
*/
- private static class Lock { }
- private static Lock lock = new Lock();
+ private static native Reference<Object> getReferencePendingList();
- /* 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 {
private static void ensureClassInitialized(Class<?> clazz) {
@@ -137,14 +127,12 @@
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);
+ // pre-load and initialize Cleaner class so that we don't get into trouble later in
+ // the run loop if there's memory shortage while loading/initializing them lazily.
ensureClassInitialized(Cleaner.class);
}
ReferenceHandler(ThreadGroup g, String name) {
super(g, null, name, 0, false);
@@ -172,53 +160,44 @@
* 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;
+ if (!waitForNotify) {
+ // FIXME! Calls from non-blocking helper threads not yet supported.
+ return false;
}
+ // Get pending references from the VM
+ Reference<Object> pending_list = getReferencePendingList();
+
+ // Enqueue references
+ while (pending_list != null) {
+ // Unlink
+ Reference<Object> r = pending_list;
+ pending_list = r.discovered;
+ r.discovered = null;
+
// Fast path for cleaners
- if (c != null) {
- c.clean();
- return true;
+ if (r instanceof Cleaner) {
+ try {
+ ((Cleaner)r).clean();
+ } catch (Throwable x) {
+ // Ignored
+ }
+
+ // Don't enqueue
+ continue;
}
+ // Enqueue
ReferenceQueue<? super Object> q = r.queue;
- if (q != ReferenceQueue.NULL) q.enqueue(r);
+ if (q != ReferenceQueue.NULL) {
+ q.enqueue(r);
+ }
+ }
+
return true;
}
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
< prev index next >