Path: blob/master/src/java.desktop/share/classes/sun/java2d/Disposer.java
41152 views
/*1* Copyright (c) 2002, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.java2d;2627import sun.awt.util.ThreadGroupUtils;2829import java.lang.ref.Reference;30import java.lang.ref.ReferenceQueue;31import java.lang.ref.PhantomReference;32import java.lang.ref.WeakReference;33import java.security.AccessController;34import java.security.PrivilegedAction;35import java.util.ArrayList;36import java.util.Hashtable;3738/**39* This class is used for registering and disposing the native40* data associated with java objects.41*42* The object can register itself by calling one of the addRecord43* methods and providing either the pointer to the native disposal44* method or a descendant of the DisposerRecord class with overridden45* dispose() method.46*47* When the object becomes unreachable, the dispose() method48* of the associated DisposerRecord object will be called.49*50* @see DisposerRecord51*/52@SuppressWarnings("removal")53public class Disposer implements Runnable {54private static final ReferenceQueue<Object> queue = new ReferenceQueue<>();55private static final Hashtable<java.lang.ref.Reference<Object>, DisposerRecord> records =56new Hashtable<>();5758private static Disposer disposerInstance;59public static final int WEAK = 0;60public static final int PHANTOM = 1;61public static int refType = PHANTOM;6263static {64java.security.AccessController.doPrivileged(65new java.security.PrivilegedAction<Void>() {66public Void run() {67System.loadLibrary("awt");68return null;69}70});71initIDs();72String type = java.security.AccessController.doPrivileged(73new sun.security.action.GetPropertyAction("sun.java2d.reftype"));74if (type != null) {75if (type.equals("weak")) {76refType = WEAK;77System.err.println("Using WEAK refs");78} else {79refType = PHANTOM;80System.err.println("Using PHANTOM refs");81}82}83disposerInstance = new Disposer();84AccessController.doPrivileged((PrivilegedAction<Void>) () -> {85String name = "Java2D Disposer";86ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup();87Thread t = new Thread(rootTG, disposerInstance, name, 0, false);88t.setContextClassLoader(null);89t.setDaemon(true);90t.setPriority(Thread.MAX_PRIORITY);91t.start();92return null;93});94}9596/**97* Registers the object and the native data for later disposal.98* @param target Object to be registered99* @param disposeMethod pointer to the native disposal method100* @param pData pointer to the data to be passed to the101* native disposal method102*/103public static void addRecord(Object target,104long disposeMethod, long pData)105{106disposerInstance.add(target,107new DefaultDisposerRecord(disposeMethod, pData));108}109110/**111* Registers the object and the native data for later disposal.112* @param target Object to be registered113* @param rec the associated DisposerRecord object114* @see DisposerRecord115*/116public static void addRecord(Object target, DisposerRecord rec) {117disposerInstance.add(target, rec);118}119120/**121* Performs the actual registration of the target object to be disposed.122* @param target Object to be registered, or if target is an instance123* of DisposerTarget, its associated disposer referent124* will be the Object that is registered125* @param rec the associated DisposerRecord object126* @see DisposerRecord127*/128synchronized void add(Object target, DisposerRecord rec) {129if (target instanceof DisposerTarget) {130target = ((DisposerTarget)target).getDisposerReferent();131}132java.lang.ref.Reference<Object> ref;133if (refType == PHANTOM) {134ref = new PhantomReference<>(target, queue);135} else {136ref = new WeakReference<>(target, queue);137}138records.put(ref, rec);139}140141public void run() {142while (true) {143try {144Object obj = queue.remove();145((Reference)obj).clear();146DisposerRecord rec = records.remove(obj);147rec.dispose();148obj = null;149rec = null;150clearDeferredRecords();151} catch (Exception e) {152System.out.println("Exception while removing reference.");153}154}155}156157/*158* This is a marker interface that, if implemented, means it159* doesn't acquire any special locks, and is safe to160* be disposed in the poll loop on whatever thread161* which happens to be the Toolkit thread, is in use.162*/163public static interface PollDisposable {164};165166private static ArrayList<DisposerRecord> deferredRecords = null;167168private static void clearDeferredRecords() {169if (deferredRecords == null || deferredRecords.isEmpty()) {170return;171}172for (int i=0;i<deferredRecords.size(); i++) {173try {174DisposerRecord rec = deferredRecords.get(i);175rec.dispose();176} catch (Exception e) {177System.out.println("Exception while disposing deferred rec.");178}179}180deferredRecords.clear();181}182183/*184* Set to indicate the queue is presently being polled.185*/186public static volatile boolean pollingQueue = false;187188/*189* The pollRemove() method is called back from a dispose method190* that is running on the toolkit thread and wants to191* dispose any pending refs that are safe to be disposed192* on that thread.193*/194public static void pollRemove() {195196/* This should never be called recursively, so this check197* is just a safeguard against the unexpected.198*/199if (pollingQueue) {200return;201}202Object obj;203pollingQueue = true;204int freed = 0;205int deferred = 0;206try {207while ( freed < 10000 && deferred < 100 &&208(obj = queue.poll()) != null ) {209freed++;210((Reference)obj).clear();211DisposerRecord rec = records.remove(obj);212if (rec instanceof PollDisposable) {213rec.dispose();214obj = null;215rec = null;216} else {217if (rec == null) { // shouldn't happen, but just in case.218continue;219}220deferred++;221if (deferredRecords == null) {222deferredRecords = new ArrayList<DisposerRecord>(5);223}224deferredRecords.add(rec);225}226}227} catch (Exception e) {228System.out.println("Exception while removing reference.");229} finally {230pollingQueue = false;231}232}233234private static native void initIDs();235236/*237* This was added for use by the 2D font implementation to avoid creation238* of an additional disposer thread.239* WARNING: this thread class monitors a specific queue, so a reference240* added here must have been created with this queue. Failure to do241* so will clutter the records hashmap and no one will be cleaning up242* the reference queue.243*/244@SuppressWarnings("unchecked")245public static void addReference(Reference<Object> ref, DisposerRecord rec) {246records.put(ref, rec);247}248249public static void addObjectRecord(Object obj, DisposerRecord rec) {250records.put(new WeakReference<>(obj, queue) , rec);251}252253/* This is intended for use in conjunction with addReference(..)254*/255public static ReferenceQueue<Object> getQueue() {256return queue;257}258259}260261262