Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/sun/java2d/Disposer.java
38829 views
/*1* Copyright (c) 2002, 2014, 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.misc.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*/52public class Disposer implements Runnable {53private static final ReferenceQueue queue = new ReferenceQueue();54private static final Hashtable records = new Hashtable();5556private static Disposer disposerInstance;57public static final int WEAK = 0;58public static final int PHANTOM = 1;59public static int refType = PHANTOM;6061static {62java.security.AccessController.doPrivileged(63new java.security.PrivilegedAction<Void>() {64public Void run() {65System.loadLibrary("awt");66return null;67}68});69initIDs();70String type = (String) java.security.AccessController.doPrivileged(71new sun.security.action.GetPropertyAction("sun.java2d.reftype"));72if (type != null) {73if (type.equals("weak")) {74refType = WEAK;75System.err.println("Using WEAK refs");76} else {77refType = PHANTOM;78System.err.println("Using PHANTOM refs");79}80}81disposerInstance = new Disposer();82AccessController.doPrivileged(83(PrivilegedAction<Void>) () -> {84/* The thread must be a member of a thread group85* which will not get GCed before VM exit.86* Make its parent the top-level thread group.87*/88ThreadGroup rootTG = ThreadGroupUtils.getRootThreadGroup();89Thread t = new Thread(rootTG, disposerInstance, "Java2D Disposer");90t.setContextClassLoader(null);91t.setDaemon(true);92t.setPriority(Thread.MAX_PRIORITY);93t.start();94return null;95}96);97}9899/**100* Registers the object and the native data for later disposal.101* @param target Object to be registered102* @param disposeMethod pointer to the native disposal method103* @param pData pointer to the data to be passed to the104* native disposal method105*/106public static void addRecord(Object target,107long disposeMethod, long pData)108{109disposerInstance.add(target,110new DefaultDisposerRecord(disposeMethod, pData));111}112113/**114* Registers the object and the native data for later disposal.115* @param target Object to be registered116* @param rec the associated DisposerRecord object117* @see DisposerRecord118*/119public static void addRecord(Object target, DisposerRecord rec) {120disposerInstance.add(target, rec);121}122123/**124* Performs the actual registration of the target object to be disposed.125* @param target Object to be registered, or if target is an instance126* of DisposerTarget, its associated disposer referent127* will be the Object that is registered128* @param rec the associated DisposerRecord object129* @see DisposerRecord130*/131synchronized void add(Object target, DisposerRecord rec) {132if (target instanceof DisposerTarget) {133target = ((DisposerTarget)target).getDisposerReferent();134}135java.lang.ref.Reference ref;136if (refType == PHANTOM) {137ref = new PhantomReference(target, queue);138} else {139ref = new WeakReference(target, queue);140}141records.put(ref, rec);142}143144public void run() {145while (true) {146try {147Object obj = queue.remove();148((Reference)obj).clear();149DisposerRecord rec = (DisposerRecord)records.remove(obj);150rec.dispose();151obj = null;152rec = null;153clearDeferredRecords();154} catch (Exception e) {155System.out.println("Exception while removing reference.");156}157}158}159160/*161* This is a marker interface that, if implemented, means it162* doesn't acquire any special locks, and is safe to163* be disposed in the poll loop on whatever thread164* which happens to be the Toolkit thread, is in use.165*/166public static interface PollDisposable {167};168169private static ArrayList<DisposerRecord> deferredRecords = null;170171private static void clearDeferredRecords() {172if (deferredRecords == null || deferredRecords.isEmpty()) {173return;174}175for (int i=0;i<deferredRecords.size(); i++) {176try {177DisposerRecord rec = deferredRecords.get(i);178rec.dispose();179} catch (Exception e) {180System.out.println("Exception while disposing deferred rec.");181}182}183deferredRecords.clear();184}185186/*187* Set to indicate the queue is presently being polled.188*/189public static volatile boolean pollingQueue = false;190191/*192* The pollRemove() method is called back from a dispose method193* that is running on the toolkit thread and wants to194* dispose any pending refs that are safe to be disposed195* on that thread.196*/197public static void pollRemove() {198199/* This should never be called recursively, so this check200* is just a safeguard against the unexpected.201*/202if (pollingQueue) {203return;204}205Object obj;206pollingQueue = true;207int freed = 0;208int deferred = 0;209try {210while ((obj = queue.poll()) != null211&& freed < 10000 && deferred < 100) {212freed++;213((Reference)obj).clear();214DisposerRecord rec = (DisposerRecord)records.remove(obj);215if (rec instanceof PollDisposable) {216rec.dispose();217obj = null;218rec = null;219} else {220if (rec == null) { // shouldn't happen, but just in case.221continue;222}223deferred++;224if (deferredRecords == null) {225deferredRecords = new ArrayList<DisposerRecord>(5);226}227deferredRecords.add(rec);228}229}230} catch (Exception e) {231System.out.println("Exception while removing reference.");232} finally {233pollingQueue = false;234}235}236237private static native void initIDs();238239/*240* This was added for use by the 2D font implementation to avoid creation241* of an additional disposer thread.242* WARNING: this thread class monitors a specific queue, so a reference243* added here must have been created with this queue. Failure to do244* so will clutter the records hashmap and no one will be cleaning up245* the reference queue.246*/247public static void addReference(Reference ref, DisposerRecord rec) {248records.put(ref, rec);249}250251public static void addObjectRecord(Object obj, DisposerRecord rec) {252records.put(new WeakReference(obj, queue) , rec);253}254255/* This is intended for use in conjunction with addReference(..)256*/257public static ReferenceQueue getQueue() {258return queue;259}260261}262263264