9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.ref;
27
28 import sun.misc.Cleaner;
29
30 /**
31 * Abstract base class for reference objects. This class defines the
32 * operations common to all reference objects. Because reference objects are
33 * implemented in close cooperation with the garbage collector, this class may
34 * not be subclassed directly.
35 *
36 * @author Mark Reinhold
37 * @since 1.2
38 */
39
40 public abstract class Reference<T> {
41
42 /* A Reference instance is in one of four possible internal states:
43 *
44 * Active: Subject to special treatment by the garbage collector. Some
45 * time after the collector detects that the reachability of the
46 * referent has changed to the appropriate state, it changes the
47 * instance's state to either Pending or Inactive, depending upon
48 * whether or not the instance was registered with a queue when it was
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);
|
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 package java.lang.ref;
27
28 import sun.misc.Cleaner;
29 import sun.misc.Unsafe;
30
31 /**
32 * Abstract base class for reference objects. This class defines the
33 * operations common to all reference objects. Because reference objects are
34 * implemented in close cooperation with the garbage collector, this class may
35 * not be subclassed directly.
36 *
37 * @author Mark Reinhold
38 * @since 1.2
39 */
40
41 public abstract class Reference<T> {
42
43 /* A Reference instance is in one of four possible internal states:
44 *
45 * Active: Subject to special treatment by the garbage collector. Some
46 * time after the collector detects that the reachability of the
47 * referent has changed to the appropriate state, it changes the
48 * instance's state to either Pending or Inactive, depending upon
49 * whether or not the instance was registered with a queue when it was
110 /* Object used to synchronize with the garbage collector. The collector
111 * must acquire this lock at the beginning of each collection cycle. It is
112 * therefore critical that any code holding this lock complete as quickly
113 * as possible, allocate no new objects, and avoid calling user code.
114 */
115 static private class Lock { };
116 private static Lock lock = new Lock();
117
118
119 /* List of References waiting to be enqueued. The collector adds
120 * References to this list, while the Reference-handler thread removes
121 * them. This list is protected by the above lock object. The
122 * list uses the discovered field to link its elements.
123 */
124 private static Reference<Object> pending = null;
125
126 /* High-priority thread to enqueue pending References
127 */
128 private static class ReferenceHandler extends Thread {
129
130 static {
131 // pre-load and initialize InterruptedException and Cleaner classes
132 // so that we don't get into trouble later in the run loop if there's
133 // memory shortage while loading/initializing them lazily.
134 Unsafe unsafe = Unsafe.getUnsafe();
135 unsafe.ensureClassInitialized(InterruptedException.class);
136 unsafe.ensureClassInitialized(Cleaner.class);
137 }
138
139 ReferenceHandler(ThreadGroup g, String name) {
140 super(g, name);
141 }
142
143 public void run() {
144 for (;;) {
145 Reference<Object> r;
146 Cleaner c;
147 try {
148 synchronized (lock) {
149 r = pending;
150 if (r != null) {
151 // 'instanceof' might throw OOME sometimes so do this before
152 // unlinking 'r' from the 'pending' chain...
153 c = r instanceof Cleaner ? (Cleaner) r : null;
154 // unlink 'r' from 'pending' chain
155 pending = r.discovered;
156 r.discovered = null;
157 } else {
158 // The waiting on the lock may cause an OOME because it may try to allocate
159 // exception objects.
160 lock.wait();
161 continue;
162 }
163 }
164 } catch (OutOfMemoryError x) {
165 // Catch OOME from 'r instanceof Cleaner' or 'lock.wait()'.
166 // Give other threads CPU time so they hopefully drop some live references
167 // and GC reclaims some space.
168 // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
169 // persistently throws OOME for some time...
170 Thread.yield();
171 // retry
172 continue;
173 } catch (InterruptedException x) {
174 // Catch InterruptedException from 'lock.wait()' and retry
175 continue;
176 }
177
178 // Fast path for cleaners
179 if (c != null) {
180 c.clean();
181 continue;
182 }
183
184 ReferenceQueue<Object> q = r.queue;
185 if (q != ReferenceQueue.NULL) q.enqueue(r);
186 }
187 }
188 }
189
190 static {
191 ThreadGroup tg = Thread.currentThread().getThreadGroup();
192 for (ThreadGroup tgn = tg;
193 tgn != null;
194 tg = tgn, tgn = tg.getParent());
195 Thread handler = new ReferenceHandler(tg, "Reference Handler");
196 /* If there were a special system-only priority greater than
197 * MAX_PRIORITY, it would be used here
198 */
199 handler.setPriority(Thread.MAX_PRIORITY);
200 handler.setDaemon(true);
|