1 /* 2 * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 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 sun.java2d; 27 28 import java.lang.ref.Reference; 29 import java.lang.ref.ReferenceQueue; 30 import java.lang.ref.PhantomReference; 31 import java.lang.ref.WeakReference; 32 import java.util.ArrayList; 33 import java.util.Hashtable; 34 35 /** 36 * This class is used for registering and disposing the native 37 * data associated with java objects. 38 * 39 * The object can register itself by calling one of the addRecord 40 * methods and providing either the pointer to the native disposal 41 * method or a descendant of the DisposerRecord class with overridden 42 * dispose() method. 43 * 44 * When the object becomes unreachable, the dispose() method 45 * of the associated DisposerRecord object will be called. 46 * 47 * @see DisposerRecord 48 */ 49 public class Disposer implements Runnable { 50 private static final ReferenceQueue queue = new ReferenceQueue(); 51 private static final Hashtable records = new Hashtable(); 52 53 private static Disposer disposerInstance; 54 public static final int WEAK = 0; 55 public static final int PHANTOM = 1; 56 public static int refType = PHANTOM; 57 58 static { 59 java.security.AccessController.doPrivileged( 60 new java.security.PrivilegedAction<Void>() { 61 public Void run() { 62 System.loadLibrary("awt"); 63 return null; 64 } 65 }); 66 initIDs(); 67 String type = java.security.AccessController.doPrivileged( 68 new sun.security.action.GetPropertyAction("sun.java2d.reftype")); 69 if (type != null) { 70 if (type.equals("weak")) { 71 refType = WEAK; 72 System.err.println("Using WEAK refs"); 73 } else { 74 refType = PHANTOM; 75 System.err.println("Using PHANTOM refs"); 76 } 77 } 78 disposerInstance = new Disposer(); 79 java.security.AccessController.doPrivileged( 80 new java.security.PrivilegedAction() { 81 public Object run() { 82 /* The thread must be a member of a thread group 83 * which will not get GCed before VM exit. 84 * Make its parent the top-level thread group. 85 */ 86 ThreadGroup tg = Thread.currentThread().getThreadGroup(); 87 for (ThreadGroup tgn = tg; 88 tgn != null; 89 tg = tgn, tgn = tg.getParent()); 90 Thread t = 91 new Thread(tg, disposerInstance, "Java2D Disposer"); 92 t.setContextClassLoader(null); 93 t.setDaemon(true); 94 t.setPriority(Thread.MAX_PRIORITY); 95 t.start(); 96 return null; 97 } 98 } 99 ); 100 } 101 102 /** 103 * Registers the object and the native data for later disposal. 104 * @param target Object to be registered 105 * @param disposeMethod pointer to the native disposal method 106 * @param pData pointer to the data to be passed to the 107 * native disposal method 108 */ 109 public static void addRecord(Object target, 110 long disposeMethod, long pData) 111 { 112 disposerInstance.add(target, 113 new DefaultDisposerRecord(disposeMethod, pData)); 114 } 115 116 /** 117 * Registers the object and the native data for later disposal. 118 * @param target Object to be registered 119 * @param rec the associated DisposerRecord object 120 * @see DisposerRecord 121 */ 122 public static void addRecord(Object target, DisposerRecord rec) { 123 disposerInstance.add(target, rec); 124 } 125 126 /** 127 * Performs the actual registration of the target object to be disposed. 128 * @param target Object to be registered, or if target is an instance 129 * of DisposerTarget, its associated disposer referent 130 * will be the Object that is registered 131 * @param rec the associated DisposerRecord object 132 * @see DisposerRecord 133 */ 134 synchronized void add(Object target, DisposerRecord rec) { 135 if (target instanceof DisposerTarget) { 136 target = ((DisposerTarget)target).getDisposerReferent(); 137 } 138 java.lang.ref.Reference ref; 139 if (refType == PHANTOM) { 140 ref = new PhantomReference(target, queue); 141 } else { 142 ref = new WeakReference(target, queue); 143 } 144 records.put(ref, rec); 145 } 146 147 public void run() { 148 while (true) { 149 try { 150 Object obj = queue.remove(); 151 ((Reference)obj).clear(); 152 DisposerRecord rec = (DisposerRecord)records.remove(obj); 153 rec.dispose(); 154 obj = null; 155 rec = null; 156 clearDeferredRecords(); 157 } catch (Exception e) { 158 System.out.println("Exception while removing reference."); 159 } 160 } 161 } 162 163 /* 164 * This is a marker interface that, if implemented, means it 165 * doesn't acquire any special locks, and is safe to 166 * be disposed in the poll loop on whatever thread 167 * which happens to be the Toolkit thread, is in use. 168 */ 169 public static interface PollDisposable { 170 }; 171 172 private static ArrayList<DisposerRecord> deferredRecords = null; 173 174 private static void clearDeferredRecords() { 175 if (deferredRecords == null || deferredRecords.isEmpty()) { 176 return; 177 } 178 for (int i=0;i<deferredRecords.size(); i++) { 179 try { 180 DisposerRecord rec = deferredRecords.get(i); 181 rec.dispose(); 182 } catch (Exception e) { 183 System.out.println("Exception while disposing deferred rec."); 184 } 185 } 186 deferredRecords.clear(); 187 } 188 189 /* 190 * Set to indicate the queue is presently being polled. 191 */ 192 public static volatile boolean pollingQueue = false; 193 194 /* 195 * The pollRemove() method is called back from a dispose method 196 * that is running on the toolkit thread and wants to 197 * dispose any pending refs that are safe to be disposed 198 * on that thread. 199 */ 200 public static void pollRemove() { 201 202 /* This should never be called recursively, so this check 203 * is just a safeguard against the unexpected. 204 */ 205 if (pollingQueue) { 206 return; 207 } 208 Object obj; 209 pollingQueue = true; 210 int freed = 0; 211 int deferred = 0; 212 try { 213 while ((obj = queue.poll()) != null 214 && freed < 10000 && deferred < 100) { 215 freed++; 216 ((Reference)obj).clear(); 217 DisposerRecord rec = (DisposerRecord)records.remove(obj); 218 if (rec instanceof PollDisposable) { 219 rec.dispose(); 220 obj = null; 221 rec = null; 222 } else { 223 if (rec == null) { // shouldn't happen, but just in case. 224 continue; 225 } 226 deferred++; 227 if (deferredRecords == null) { 228 deferredRecords = new ArrayList<DisposerRecord>(5); 229 } 230 deferredRecords.add(rec); 231 } 232 } 233 } catch (Exception e) { 234 System.out.println("Exception while removing reference."); 235 } finally { 236 pollingQueue = false; 237 } 238 } 239 240 private static native void initIDs(); 241 242 /* 243 * This was added for use by the 2D font implementation to avoid creation 244 * of an additional disposer thread. 245 * WARNING: this thread class monitors a specific queue, so a reference 246 * added here must have been created with this queue. Failure to do 247 * so will clutter the records hashmap and no one will be cleaning up 248 * the reference queue. 249 */ 250 public static void addReference(Reference ref, DisposerRecord rec) { 251 records.put(ref, rec); 252 } 253 254 public static void addObjectRecord(Object obj, DisposerRecord rec) { 255 records.put(new WeakReference(obj, queue) , rec); 256 } 257 258 /* This is intended for use in conjunction with addReference(..) 259 */ 260 public static ReferenceQueue getQueue() { 261 return queue; 262 } 263 264 }