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