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