79 * to determine whether a Reference instance requires special treatment: If 80 * the next field is null then the instance is active; if it is non-null, 81 * then the collector should treat the instance normally. 82 * 83 * To ensure that a concurrent collector can discover active Reference 84 * objects without interfering with application threads that may apply 85 * the enqueue() method to those objects, collectors should link 86 * discovered objects through the discovered field. The discovered 87 * field is also used for linking Reference objects in the pending list. 88 */ 89 90 private T referent; /* Treated specially by GC */ 91 92 volatile ReferenceQueue<? super T> queue; 93 94 /* When active: NULL 95 * pending: this 96 * Enqueued: next reference in queue (or this if last) 97 * Inactive: this 98 */ 99 Reference next; 100 101 /* When active: next element in a discovered reference list maintained by GC (or this if last) 102 * pending: next element in the pending list (or null if last) 103 * otherwise: NULL 104 */ 105 transient private Reference<T> discovered; /* used by VM */ 106 107 108 /* Object used to synchronize with the garbage collector. The collector 109 * must acquire this lock at the beginning of each collection cycle. It is 110 * therefore critical that any code holding this lock complete as quickly 111 * as possible, allocate no new objects, and avoid calling user code. 112 */ 113 static private class Lock { }; 114 private static Lock lock = new Lock(); 115 116 117 /* List of References waiting to be enqueued. The collector adds 118 * References to this list, while the Reference-handler thread removes 119 * them. This list is protected by the above lock object. The 120 * list uses the discovered field to link its elements. 121 */ 122 private static Reference pending = null; 123 124 /* High-priority thread to enqueue pending References 125 */ 126 private static class ReferenceHandler extends Thread { 127 128 ReferenceHandler(ThreadGroup g, String name) { 129 super(g, name); 130 } 131 132 public void run() { 133 for (;;) { 134 Reference r; 135 synchronized (lock) { 136 if (pending != null) { 137 r = pending; 138 pending = r.discovered; 139 r.discovered = null; 140 } else { 141 // The waiting on the lock may cause an OOME because it may try to allocate 142 // exception objects, so also catch OOME here to avoid silent exit of the 143 // reference handler thread. 144 // 145 // Explicitly define the order of the two exceptions we catch here 146 // when waiting for the lock. 147 // 148 // We do not want to try to potentially load the InterruptedException class 149 // (which would be done if this was its first use, and InterruptedException 150 // were checked first) in this situation. 151 // 152 // This may lead to the VM not ever trying to load the InterruptedException 153 // class again. 154 try { 155 try { 156 lock.wait(); 157 } catch (OutOfMemoryError x) { } 158 } catch (InterruptedException x) { } 159 continue; 160 } 161 } 162 163 // Fast path for cleaners 164 if (r instanceof Cleaner) { 165 ((Cleaner)r).clean(); 166 continue; 167 } 168 169 ReferenceQueue q = r.queue; 170 if (q != ReferenceQueue.NULL) q.enqueue(r); 171 } 172 } 173 } 174 175 static { 176 ThreadGroup tg = Thread.currentThread().getThreadGroup(); 177 for (ThreadGroup tgn = tg; 178 tgn != null; 179 tg = tgn, tgn = tg.getParent()); 180 Thread handler = new ReferenceHandler(tg, "Reference Handler"); 181 /* If there were a special system-only priority greater than 182 * MAX_PRIORITY, it would be used here 183 */ 184 handler.setPriority(Thread.MAX_PRIORITY); 185 handler.setDaemon(true); 186 handler.start(); 187 } 188 189 | 79 * to determine whether a Reference instance requires special treatment: If 80 * the next field is null then the instance is active; if it is non-null, 81 * then the collector should treat the instance normally. 82 * 83 * To ensure that a concurrent collector can discover active Reference 84 * objects without interfering with application threads that may apply 85 * the enqueue() method to those objects, collectors should link 86 * discovered objects through the discovered field. The discovered 87 * field is also used for linking Reference objects in the pending list. 88 */ 89 90 private T referent; /* Treated specially by GC */ 91 92 volatile ReferenceQueue<? super T> queue; 93 94 /* When active: NULL 95 * pending: this 96 * Enqueued: next reference in queue (or this if last) 97 * Inactive: this 98 */ 99 @SuppressWarnings("rawtypes") 100 Reference next; 101 102 /* When active: next element in a discovered reference list maintained by GC (or this if last) 103 * pending: next element in the pending list (or null if last) 104 * otherwise: NULL 105 */ 106 transient private Reference<T> discovered; /* used by VM */ 107 108 109 /* Object used to synchronize with the garbage collector. The collector 110 * must acquire this lock at the beginning of each collection cycle. It is 111 * therefore critical that any code holding this lock complete as quickly 112 * as possible, allocate no new objects, and avoid calling user code. 113 */ 114 static private class Lock { }; 115 private static Lock lock = new Lock(); 116 117 118 /* List of References waiting to be enqueued. The collector adds 119 * References to this list, while the Reference-handler thread removes 120 * them. This list is protected by the above lock object. The 121 * list uses the discovered field to link its elements. 122 */ 123 private static Reference<Object> pending = null; 124 125 /* High-priority thread to enqueue pending References 126 */ 127 private static class ReferenceHandler extends Thread { 128 129 ReferenceHandler(ThreadGroup g, String name) { 130 super(g, name); 131 } 132 133 public void run() { 134 for (;;) { 135 Reference<Object> r; 136 synchronized (lock) { 137 if (pending != null) { 138 r = pending; 139 pending = r.discovered; 140 r.discovered = null; 141 } else { 142 // The waiting on the lock may cause an OOME because it may try to allocate 143 // exception objects, so also catch OOME here to avoid silent exit of the 144 // reference handler thread. 145 // 146 // Explicitly define the order of the two exceptions we catch here 147 // when waiting for the lock. 148 // 149 // We do not want to try to potentially load the InterruptedException class 150 // (which would be done if this was its first use, and InterruptedException 151 // were checked first) in this situation. 152 // 153 // This may lead to the VM not ever trying to load the InterruptedException 154 // class again. 155 try { 156 try { 157 lock.wait(); 158 } catch (OutOfMemoryError x) { } 159 } catch (InterruptedException x) { } 160 continue; 161 } 162 } 163 164 // Fast path for cleaners 165 if (r instanceof Cleaner) { 166 ((Cleaner)r).clean(); 167 continue; 168 } 169 170 ReferenceQueue<Object> q = r.queue; 171 if (q != ReferenceQueue.NULL) q.enqueue(r); 172 } 173 } 174 } 175 176 static { 177 ThreadGroup tg = Thread.currentThread().getThreadGroup(); 178 for (ThreadGroup tgn = tg; 179 tgn != null; 180 tg = tgn, tgn = tg.getParent()); 181 Thread handler = new ReferenceHandler(tg, "Reference Handler"); 182 /* If there were a special system-only priority greater than 183 * MAX_PRIORITY, it would be used here 184 */ 185 handler.setPriority(Thread.MAX_PRIORITY); 186 handler.setDaemon(true); 187 handler.start(); 188 } 189 190 |