zoukankan      html  css  js  c++  java
  • FinalizableReference, FinalizablePhantomReference, FinalizableReferenceQueue

    FinalizableReference

    /*
     * Copyright (C) 2007 The Guava Authors
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.google.common.base;
    
    /**
     * Implemented by references that have code to run after garbage collection of their referents.
     *
     * 由一些reference实现,这些reference是具有可以在他们的referents被垃圾回收后执行的代码的referent
     *
     * @see FinalizableReferenceQueue
     * @author Bob Lee
     * @since 2.0 (imported from Google Collections Library)
     */
    public interface FinalizableReference {
        /**
         * Invoked on a background thread after the referent has been garbage collected unless security
         * restrictions prevented starting a background thread, in which case this method is invoked when
         * new references are created.
         * 
         * 当referent被回收后调用一个后台线程,除非安全策略阻止启动这个安全线程,此时这个方法会在一个新的reference创建后被调用
         */
        void finalizeReferent();
    }

    FinalizablePhantomReference

    /*
     * Copyright (C) 2007 The Guava Authors
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.google.common.base;
    
    import java.lang.ref.PhantomReference;
    import java.lang.ref.ReferenceQueue;
    
    /**
     * Phantom reference with a {@code finalizeReferent()} method which a background thread invokes
     * after the garbage collector reclaims the referent. This is a simpler alternative to using a
     * {@link ReferenceQueue}.
     *
     * 一个有可以在垃圾收集器回收referent后被后台线程调用的finalizeReferent()方法的虚引用
     * 这是一个对ReferenceQueue更简单的替代
     *
     * <p>Unlike a normal phantom reference, this reference will be cleared automatically.
     * 不像一个普通的虚引用,这个引用会自动清理
     *
     * @author Bob Lee
     * @since 2.0 (imported from Google Collections Library)
     */
    public abstract class FinalizablePhantomReference<T> extends PhantomReference<T>
            implements FinalizableReference {
        /**
         * Constructs a new finalizable phantom reference.
         *
         * @param referent to phantom reference
         * @param queue that should finalize the referent
         */
        protected FinalizablePhantomReference(T referent, FinalizableReferenceQueue queue) {
            super(referent, queue.queue);
            queue.cleanUp();
        }
    }

    FinalizableReferenceQueue

    /*
     * Copyright (C) 2007 The Guava Authors
     *
     * Licensed under the Apache License, Version 2.0 (the "License");
     * you may not use this file except in compliance with the License.
     * You may obtain a copy of the License at
     *
     * http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed under the License is distributed on an "AS IS" BASIS,
     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    
    package com.google.common.base;
    
    import com.google.common.annotations.VisibleForTesting;
    
    import java.io.FileNotFoundException;
    import java.io.IOException;
    import java.lang.ref.Reference;
    import java.lang.ref.ReferenceQueue;
    import java.lang.reflect.Method;
    import java.net.URL;
    import java.net.URLClassLoader;
    import java.util.logging.Level;
    import java.util.logging.Logger;
    
    /**
     * A reference queue with an associated background thread that dequeues references and invokes
     * {@link FinalizableReference#finalizeReferent()} on them.
     *
     * 一个和后台线程关联的引用队列,他可以将引用出队并调用他们的FinalizableReference#finalizeReferent()方法
     *
     * <p>Keep a strong reference to this object until all of the associated referents have been
     * finalized. If this object is garbage collected earlier, the backing thread will not invoke {@code
     * finalizeReferent()} on the remaining references.
     *
     * 保留一个强引用给这个对象知道所有的关联引用都被终结.加入这个对象过早地被垃圾回收,后台线程将不会再调用剩余引用的finalizeReferent()
     *
     * @author Bob Lee
     * @since 2.0 (imported from Google Collections Library)
     */
    public class FinalizableReferenceQueue {
      /*
       * The Finalizer thread keeps a phantom reference to this object. When the client (for example, a
       * map built by MapMaker) no longer has a strong reference to this object, the garbage collector
       * will reclaim it and enqueue the phantom reference. The enqueued reference will trigger the
       * Finalizer to stop.
       *
       * Finalizer 线程持有这个对象的虚引用.当客户端(比如一个由MapMaker创建的Map)不再有这个对象的强引用时
       * 垃圾收集器将会回收它并将他的虚引用入队.这个入队的虚引用将会触发Finalizer的终止
       *
       * If this library is loaded in the system class loader, FinalizableReferenceQueue can load
       * Finalizer directly with no problems.
       *
       * 假如这个lib是由system class loader加载的,FinalizableReferenceQueue可以直接加载Finalizer
       *
       * If this library is loaded in an application class loader, it's important that Finalizer not
       * have a strong reference back to the class loader. Otherwise, you could have a graph like this:
       *
       * 假如这个lib是由application class loader加载的,很重要的一点是Finalizer不会持有这个class loader的强引用.
       * 另外,你可以有个图,如下:
       *
       * Finalizer Thread runs instance of -> Finalizer.class loaded by -> Application class loader
       * which loaded -> ReferenceMap.class which has a static -> FinalizableReferenceQueue instance
       *
       * Finalizer Thread 运行一个 -> Finalizer.class的实例这个Finalizer.class被 -> Application class loader 加载 ->
       * Application class loader 加载的 ReferenceMap.class, 这个ReferenceMap持有一个静态的 -> FinalizableReferenceQueue实例
       *
       * Even if no other references to classes from the application class loader remain, the Finalizer
       * thread keeps an indirect strong reference to the queue in ReferenceMap, which keeps the
       * Finalizer running, and as a result, the application class loader can never be reclaimed.
       *
       * 即使没有别的从application class loader中来的class的引用留下,Finalizer thread 也会保持一个在ReferenceMap
       * 中的这个queue的间接强引用, 这样可以保持Finalizer持续运行, 结论就是application class loader永远不会被垃圾回收
       *
       * This means that dynamically loaded web applications and OSGi bundles can't be unloaded.
       *
       * 这意味着动态加载的web应用和OSGi bundles不能被卸载
       *
       * If the library is loaded in an application class loader, we try to break the cycle by loading
       * Finalizer in its own independent class loader:
       *
       * 假如这个lib是被 application class loader 加载的,我们试图通过在他自己独立的class loader里加载Finalizer
       * 来破坏这个循环
       *
       * System class loader -> Application class loader -> ReferenceMap -> FinalizableReferenceQueue
       * -> etc. -> Decoupled class loader -> Finalizer
       *
       * Now, Finalizer no longer keeps an indirect strong reference to the static
       * FinalizableReferenceQueue field in ReferenceMap. The application class loader can be reclaimed
       * at which point the Finalizer thread will stop and its decoupled class loader can also be
       * reclaimed.
       *
       * 现在, Finalizer不在持有ReferenceMap中的static 属性FinalizableReferenceQueue的强引用了,application class loader
       * 可以在Finalizer线程停止的时候被回收,并且他的解耦的class loader也可以被回收
       *
       * If any of this fails along the way, we fall back to loading Finalizer directly in the
       * application class loader.
       *
       * 假如这种方法失败了,我们会回到使用直接在application class loader加载Finalizer的方式
       */
    
        private static final Logger logger = Logger.getLogger(FinalizableReferenceQueue.class.getName());
    
        private static final String FINALIZER_CLASS_NAME = "com.google.common.base.internal.Finalizer";
    
        /** Reference to Finalizer.startFinalizer(). */
        /** Finalizer.startFinalizer(). 方法的引用 */
        private static final Method startFinalizer;
        static {
            // TODO 分别使用SystemLoader(), DecoupledLoader, DirectLoader()来加载Finalizer
            Class<?> finalizer = loadFinalizer(
                    new SystemLoader(), new DecoupledLoader(), new DirectLoader());
            startFinalizer = getStartFinalizer(finalizer);
        }
    
        /**
         * The actual reference queue that our background thread will poll.
         *
         * 后台线程Finalizer用来clean reference的queue
         */
        final ReferenceQueue<Object> queue;
    
        /**
         * Whether or not the background thread started successfully.
         *
         * 标记后台线程是否启动成功
         */
        final boolean threadStarted;
    
        /**
         * Constructs a new queue.
         *
         * 构造方法
         */
        @SuppressWarnings("unchecked")
        public FinalizableReferenceQueue() {
            // We could start the finalizer lazily, but I'd rather it blow up early.
            // 我们会延迟启动finalizer, 但我宁愿他早点启动
            ReferenceQueue<Object> queue;
            boolean threadStarted = false;
            try {
                // TODO 这里invoke(null)是怎么做到的
                queue = (ReferenceQueue<Object>)
                        startFinalizer.invoke(null, FinalizableReference.class, this);
                threadStarted = true;
            } catch (IllegalAccessException impossible) {
                throw new AssertionError(impossible); // startFinalizer() is public
            } catch (Throwable t) {
                logger.log(Level.INFO, "Failed to start reference finalizer thread."
                        + " Reference cleanup will only occur when new references are created.", t);
                queue = new ReferenceQueue<Object>();
            }
    
            this.queue = queue;
            this.threadStarted = threadStarted;
        }
    
        /**
         * Repeatedly dequeues references from the queue and invokes {@link
         * FinalizableReference#finalizeReferent()} on them until the queue is empty. This method is a
         * no-op if the background thread was created successfully.
         *
         * 当finalizer线程启动失败的时候,手动调用cleanUp()方法来清理queue里的reference
         */
        void cleanUp() {
            if (threadStarted) {
                return;
            }
    
            Reference<?> reference;
            while ((reference = queue.poll()) != null) {
          /*
           * This is for the benefit of phantom references. Weak and soft references will have already
           * been cleared by this point.
           *
           * 这个清理的方法跟Finalizer里的cleanUp()是一样的
           */
                reference.clear();
                try {
                    ((FinalizableReference) reference).finalizeReferent();
                } catch (Throwable t) {
                    logger.log(Level.SEVERE, "Error cleaning up after reference.", t);
                }
            }
        }
    
        /**
         * Iterates through the given loaders until it finds one that can load Finalizer.
         *
         * 使用一组loader遍历加载finalizer直到加载成功
         *
         * @return Finalizer.class
         */
        private static Class<?> loadFinalizer(FinalizerLoader... loaders) {
            for (FinalizerLoader loader : loaders) {
                Class<?> finalizer = loader.loadFinalizer();
                if (finalizer != null) {
                    return finalizer;
                }
            }
    
            throw new AssertionError();
        }
    
        /**
         * Loads Finalizer.class.
         *
         * 顶一个load Finalizer的加载器
         */
        interface FinalizerLoader {
    
            /**
             * Returns Finalizer.class or null if this loader shouldn't or can't load it.
             *
             * 加载成功返回Finalizer.class
             *
             * @throws SecurityException if we don't have the appropriate privileges
             */
            Class<?> loadFinalizer();
        }
    
        /**
         * Tries to load Finalizer from the system class loader. If Finalizer is in the system class path,
         * we needn't create a separate loader.
         *
         * 尝试使用system class loader来加载Finalizer
         * 假如Finalizer已经在system class path中,则不需要再创建一个分离的loader
         */
        static class SystemLoader implements FinalizerLoader {
            // This is used by the ClassLoader-leak test in FinalizableReferenceQueueTest to disable
            // 这个变量用来给 FinalizableReferenceQueueTest 做 ClassLoader-leak 测试用
            // finding Finalizer on the system class path even if it is there.
            // 在system class path中寻找Finalizer
            @VisibleForTesting // 标记这是一个测试变量的annotation
            static boolean disabled;
    
            @Override
            public Class<?> loadFinalizer() {
                if (disabled) {
                    return null;
                }
                ClassLoader systemLoader;
                try {
                    systemLoader = ClassLoader.getSystemClassLoader();
                } catch (SecurityException e) {
                    logger.info("Not allowed to access system class loader.");
                    return null;
                }
                if (systemLoader != null) {
                    try {
                        return systemLoader.loadClass(FINALIZER_CLASS_NAME);
                    } catch (ClassNotFoundException e) {
                        // Ignore. Finalizer is simply in a child class loader.
                        // Finalizer在child class loader的情况
                        return null;
                    }
                } else {
                    return null;
                }
            }
        }
    
        /**
         * Try to load Finalizer in its own class loader. If Finalizer's thread had a direct reference to
         * our class loader (which could be that of a dynamically loaded web application or OSGi bundle),
         * it would prevent our class loader from getting garbage collected.
         *
         * 尝试使用Finalizer自己的class loader来加载Finalizer, 假如Finalizer线程有一个对我们的class loader的直接引用
         * (这可能是一个动态加载的web程序或者OSGi bundle)
         * 他将会阻止我们的class loader被垃圾回收
         */
        static class DecoupledLoader implements FinalizerLoader {
            private static final String LOADING_ERROR = "Could not load Finalizer in its own class loader."
                    + "Loading Finalizer in the current class loader instead. As a result, you will not be able"
                    + "to garbage collect this class loader. To support reclaiming this class loader, either"
                    + "resolve the underlying issue, or move Google Collections to your system class path.";
    
            @Override
            public Class<?> loadFinalizer() {
                try {
            /*
             * We use URLClassLoader because it's the only concrete class loader implementation in the
             * JDK. If we used our own ClassLoader subclass, Finalizer would indirectly reference this
             * class loader:
             *
             * 我们使用 URLClassLoader因为它是JDK中唯一各一个class loader实现
             * 假如我们使用自己的ClassLoader子类, Finalizer将会有一个间接引用到this class loader
             *
             * Finalizer.class -> CustomClassLoader -> CustomClassLoader.class -> This class loader
             *
             * System class loader will (and must) be the parent.
             *
             * System class loader 将会是(也必须是) 父 class loader
             */
                    ClassLoader finalizerLoader = newLoader(getBaseUrl());
                    return finalizerLoader.loadClass(FINALIZER_CLASS_NAME);
                } catch (Exception e) {
                    logger.log(Level.WARNING, LOADING_ERROR, e);
                    return null;
                }
            }
    
            /**
             * Gets URL for base of path containing Finalizer.class.
             *
             * 获取包含Finalizer.class的基础路径的URL
             */
            URL getBaseUrl() throws IOException {
                // Find URL pointing to Finalizer.class file.
                // 找到Finalizer.class文件的URL
                String finalizerPath = FINALIZER_CLASS_NAME.replace('.', '/') + ".class";
                URL finalizerUrl = getClass().getClassLoader().getResource(finalizerPath);
                if (finalizerUrl == null) {
                    throw new FileNotFoundException(finalizerPath);
                }
    
                // Find URL pointing to base of class path.
                // 找到class path的base URL
                String urlString = finalizerUrl.toString();
                if (!urlString.endsWith(finalizerPath)) {
                    throw new IOException("Unsupported path style: " + urlString);
                }
                // 获取Finalizer.class的base路径字符串
                urlString = urlString.substring(0, urlString.length() - finalizerPath.length());
                // 返回一个以finalizerUrl为域名,base urlString为后缀的URL
                return new URL(finalizerUrl, urlString);
            }
    
            /** Creates a class loader with the given base URL as its classpath. */
            /** 使用指定的URL创建一个class loader */
            URLClassLoader newLoader(URL base) {
                // We use the bootstrap class loader as the parent because Finalizer by design uses
                // only standard Java classes. That also means that FinalizableReferenceQueueTest
                // doesn't pick up the wrong version of the Finalizer class.
    
                // 我们使用bootstrap class loader来作为父loader因为Finalizer的设计是使用标准java类设计的
                // 也就是说FinalizableReferenceQueueTest无法找出错误的Finalizer class版本
                return new URLClassLoader(new URL[] {base}, null);
            }
        }
    
        /**
         * Loads Finalizer directly using the current class loader. We won't be able to garbage collect
         * this class loader, but at least the world doesn't end.
         *
         * 使用当前Application Class Loader直接加载Finalizer,这样我们将不能呢对这个class loader进行垃圾回收
         * 但至少这个世界不会毁灭...
         */
        static class DirectLoader implements FinalizerLoader {
            @Override
            public Class<?> loadFinalizer() {
                try {
                    return Class.forName(FINALIZER_CLASS_NAME);
                } catch (ClassNotFoundException e) {
                    throw new AssertionError(e);
                }
            }
        }
    
        /**
         * Looks up Finalizer.startFinalizer().
         *
         * 返回Finalizer的startFinalizer()方法
         */
        static Method getStartFinalizer(Class<?> finalizer) {
            try {
                return finalizer.getMethod("startFinalizer", Class.class, Object.class);
            } catch (NoSuchMethodException e) {
                throw new AssertionError(e);
            }
        }
    }
  • 相关阅读:
    window10 禁止更新
    安装node.msi 格式的文件失败
    url参数的转码和解码
    Linux12-内存管理
    C++四种cast
    Linux内核5-系统调用
    Linux内核3-进程管理
    UNIX12-线程(下)线程控制
    UNIX11-线程(上)
    Linux内核8-中断下半部和推后执行的工作(下半部)
  • 原文地址:https://www.cnblogs.com/zemliu/p/3328127.html
Copyright © 2011-2022 走看看