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

Print this page

        

@@ -171,18 +171,14 @@
      *         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

@@ -195,20 +191,39 @@
                 }
             }
         } 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;
         }
 
+        Cleaner c;
+        try {
+            // It was established that "instanceof Cleaner" can cause OOME
+            // to be thrown. The only logical explanation is that this is caused
+            // by unsuccessful loading of the Cleaner class, triggered by instanceof.
+            // So now we pre-load Cleaner class at Reference class initialization
+            // time, but we are superstitious and still catch OOME here.
+            c = (r instanceof Cleaner) ? (Cleaner) r : null;
+        } catch (OutOfMemoryError x) {
+            // Give other threads CPU time so they hopefully drop some live references
+            // and GC reclaims some space.
+            Thread.yield();
+            // re-link 'r' back to 'pending' chain
+            synchronized (lock) {
+                r.discovered = pending;
+                pending = r;
+            }
+            // retry
+            return true;
+        }
+
         // Fast path for cleaners
         if (c != null) {
             c.clean();
             return true;
         }