`

Reference

阅读更多
Reference


一、总结

1.jdk 1.8.0

2.引用级别
  • FinalReference,不对外提供使用,类的访问权限为默认 protect,即使抛出 out of memory 异常也不会回收所占内存
  • SoftReference,在内存不够用时,在抛出 out of memory 前回收内存空间
  • WeakReference,第一次GC不回收,当第二次GC时回收,有限期到第二次GC前都在内存中
  • PhantomReference


3.引用对比
-强引用软引用弱引用虚引用
定义强引用指的是,程序中有直接可达的引用,而不需要通过任何引用对象,如Object obj = new Object();中,obj为强引用软引用,非强引用,但是可以通过软引用对象来访问。软引用的对象,只有在内存不足的时候(抛出OOM异常前),垃圾收集器会决定回收该软引用所指向的对象。软引用通常用于实现内存敏感的缓存。弱引用,非强引用和软引用,但是可以通过弱引用对象来访问。弱引用的对象,不管内存是否足够,只要被垃圾收集器发现,该引用的对象就会被回收。实际的应用见WeakHashMap虚引用,该引用必须和引用队列(ReferenceQueue)一起使用,一般用于实现追踪垃圾收集器的回收动作,比如在对象被回收的时候,会调用该对象的finalize方法,在使用虚引用可以实现该动作,也更加安全


4.其他
  • 子类不可直接继承;处于安全考虑,Reference 类与GC交互;实现方式:构造方法的访问权限为默认,即包外的类不可见
  • 对象封装了其它对象的引用,可以和普通的对象一样操作,在一定的限制条件下,支持和垃圾收集器的交互。即可以使用Reference对象来引用其它对象,但是最后还是会被垃圾收集器回收。程序有时候也需要在对象回收后被通知,以告知对象的可达性发生变更


5.流程




二、源码分析


/**
 * Abstract base class for reference objects.  This class defines the
 * operations common to all reference objects.  Because reference objects are
 * implemented in close cooperation with the garbage collector, this class may
 * not be subclassed directly.
 *
 * @author   Mark Reinhold
 * @since    1.2
 */

public abstract class Reference<T> {


类的注释:
  • Reference 类是引用对象的抽象基类
  • Reference 类中定义了引用对象的常用操作
  • 由于引用对象是通过与垃圾回收器密切合作来实现的,因此,不能直接为此类创建子类


Reference 类不能被包外的类继承的实现:
  • Reference 类的构造方法的访问权限为默认,即同包内的类可见
  • 子类的构造方法默认通过  super() 调用父类的构造方法,访问不到父类的构造方法

    // 构造方法,两个
    // 区别:是否带有 ReferenceQueue 参数
    // 不带有  ReferenceQueue 参数的构造方法,当 Reference 被 GC 回收后直接由 Active 状态变为 InActive 状态
    
    Reference(T referent) {
        this(referent, null);
    }

    Reference(T referent, ReferenceQueue<? super T> queue) {
        this.referent = referent;
        this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
    }

    // 带有 ReferenceQueue 参数的构造方法,当 Reference 被 GC 回收后会被加入到 GC 自动加入到 pending-Reference list 中,即类中的属性 pengding  
    private static Reference<Object> pending = null;

    // 对应构造方法传入的两个参数
    private T referent;         /* Treated specially by GC */
    volatile ReferenceQueue<? super T> queue;



    // 不同状态队列的next元素
    /* When active:   NULL
     *     pending:   this
     *    Enqueued:   next reference in queue (or this if last)
     *    Inactive:   this
     */
    @SuppressWarnings("rawtypes")
    Reference next;


  • 使用:访问权限为默认,当前类中未使用到该属性;为同包中其他类中调用使用,如:ReferenceQueue 中使用到了
  • 作用:Reference 数据结构为链表,用于连接后续的对象
  • Reference next , 在  ReferenceQueue  中指代构造方法传入的参数中的  ReferenceQueue


Reference状态ReferenceQueue中的next的指向
ActiveNULL
Pending本身
Enqueued下一个元素或本身(尾部的元素指向本身)
InactiveNULL


 /* A Reference instance is in one of four possible internal states:
     *
     *     Active: Subject to special treatment by the garbage collector.  Some
     *     time after the collector detects that the reachability of the
     *     referent has changed to the appropriate state, it changes the
     *     instance's state to either Pending or Inactive, depending upon
     *     whether or not the instance was registered with a queue when it was
     *     created.  In the former case it also adds the instance to the
     *     pending-Reference list.  Newly-created instances are Active.
     *
     *     Pending: An element of the pending-Reference list, waiting to be
     *     enqueued by the Reference-handler thread.  Unregistered instances
     *     are never in this state.
     *
     *     Enqueued: An element of the queue with which the instance was
     *     registered when it was created.  When an instance is removed from
     *     its ReferenceQueue, it is made Inactive.  Unregistered instances are
     *     never in this state.
     *
     *     Inactive: Nothing more to do.  Once an instance becomes Inactive its
     *     state will never change again.
     *
     * The state is encoded in the queue and next fields as follows:
     *
     *     Active: queue = ReferenceQueue with which instance is registered, or
     *     ReferenceQueue.NULL if it was not registered with a queue; next =
     *     null.
     *
     *     Pending: queue = ReferenceQueue with which instance is registered;
     *     next = this
     *
     *     Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
     *     in queue, or this if at end of list.
     *
     *     Inactive: queue = ReferenceQueue.NULL; next = this.
     *
     * With this scheme the collector need only examine the next field in order
     * to determine whether a Reference instance requires special treatment: If
     * the next field is null then the instance is active; if it is non-null,
     * then the collector should treat the instance normally.
     *
     * To ensure that a concurrent collector can discover active Reference
     * objects without interfering with application threads that may apply
     * the enqueue() method to those objects, collectors should link
     * discovered objects through the discovered field. The discovered
     * field is also used for linking Reference objects in the pending list.
     */
    // 用于保存对象的引用,GC会根据不同Reference来特别对待,构造方法的参数
    private T referent;         /* Treated specially by GC */
    
    // 简述:如果需要通知机制,则保存的对对应的队列
    // 使用:构造方法的参数
    // 作用:创建Reference时,将Queue注册到Reference中,当该Reference所引用的对象
    // 被垃圾收集器回收时,会将该Reference放到该队列中,相当于一种通知机制
    volatile ReferenceQueue<? super T> queue;

    /* When active:   next element in a discovered reference list maintained by GC (or this if last)
     *     pending:   next element in the pending list (or null if last)
     *   otherwise:   NULL
     */
    // 指向队列中的下一个对象;不同于next,为当前类中使用
    transient private Reference<T> discovered;  /* used by VM */

    /* Object used to synchronize with the garbage collector.  The collector
     * must acquire this lock at the beginning of each collection cycle.  It is
     * therefore critical that any code holding this lock complete as quickly
     * as possible, allocate no new objects, and avoid calling user code.
     */
    static private class Lock { }
    private static Lock lock = new Lock();

    /* List of References waiting to be enqueued.  The collector adds
     * References to this list, while the Reference-handler thread removes
     * them.  This list is protected by the above lock object. The
     * list uses the discovered field to link its elements.
     */
    // 等待进行 enqueued 操作的对象集合;
    // 当 Reference-handler 线程删除元素后,GC 将删除的元素加入此队列中;
    // 此集合通过上述的 lock 锁实现线程安全
    // 此集合通过 discovered 属性链接本身的元素
    // pending队列中的元素由GC自动加入(对象回收后放入此队列中)
    private static Reference<Object> pending = null;


由类中的属性得知:内部的数据结果是单链表

ReferenceQueue<? super T> queue 的作用
  • queue 通过构造方法传入,若无默认为 null,用于存入注册到队列上的引用对象
  • queue 区分不同状态的  Reference ,不同的状态对应不同的queue



Reference有4种状态
  • Active:Active状态的Reference会受到GC的特别关注,当GC察觉到引用的可达性变化为其它的状态之后,它的状态将变化为Pending或Inactive,到底转化为Pending状态还是Inactive状态取决于此Reference对象创建时是否注册了queue.如果注册了queue,则将添加此实例到pending-Reference list中。 新创建的Reference实例的状态是Active。
  • Pending:在pending-Reference list中等待着被Reference-handler 线程入队列queue中的元素就处于这个状态。没有注册queue的实例是永远不可能到达这一状态
  • Enqueued:队列中的对象的状态,当实例被移动到ReferenceQueue外时,Reference的状态为Inactive。没有注册ReferenceQueue的不可能到达这一状态的
  • Inactive:一旦一个实例变为Inactive,则这个状态永远都不会再被改变


Reference四种状态对应的队列
  • Active queue:刚创建的队列或队列中没有对象注入;next = null ;由构造方法可知,新创建的实例都处于此状态
  • Pending queue:
  • Enqueued queue:
  • Inactive queue:


    /* High-priority thread to enqueue pending References
     */
    private static class ReferenceHandler extends Thread {

        private static void ensureClassInitialized(Class<?> clazz) {
            try {
                Class.forName(clazz.getName(), true, clazz.getClassLoader());
            } catch (ClassNotFoundException e) {
                throw (Error) new NoClassDefFoundError(e.getMessage()).initCause(e);
            }
        }

        static {
            // pre-load and initialize InterruptedException and Cleaner classes
            // so that we don't get into trouble later in the run loop if there's
            // memory shortage while loading/initializing them lazily.
            ensureClassInitialized(InterruptedException.class);
            ensureClassInitialized(Cleaner.class);
        }

        ReferenceHandler(ThreadGroup g, String name) {
            super(g, name);
        }

        public void run() {
            while (true) {
                tryHandlePending(true);
            }
        }
    }





    /**
     * Try handle pending {@link Reference} if there is one.<p>
     * Return {@code true} as a hint that there might be another
     * {@link Reference} pending or {@code false} when there are no more pending
     * {@link Reference}s at the moment and the program can do some other
     * useful work instead of looping.
     *
     * @param waitForNotify if {@code true} and there was no pending
     *                      {@link Reference}, wait until notified from VM
     *                      or interrupted; if {@code false}, return immediately
     *                      when there is no pending {@link Reference}.
     * @return {@code true} if there was a {@link Reference} pending and it
     *         was processed, or we waited for notification and either got it
     *         or thread was interrupted before being notified;
     *         {@code false} otherwise.
     */
    static boolean tryHandlePending(boolean waitForNotify) {
        Reference<Object> r;
        Cleaner c; // PhantomReference 的子类
        try {
            synchronized (lock) {
                // pengding Reference Queue 不为空
                if (pending != null) {
                    r = pending; // 将 pending 赋值给 r 
                    // 'instanceof' might throw OutOfMemoryError sometimes
                    // so do this before un-linking 'r' from the 'pending' chain...
                    // r 是否是 Cleaner 的实例对象
                    c = r instanceof Cleaner ? (Cleaner) r : null; 
                    // unlink 'r' from 'pending' chain
                    // pengding 指向下一个元素
                    pending = r.discovered;
                    r.discovered = null;
                } else {
                    // pending Reference Queue 为空
                    // The waiting on the lock may cause an OutOfMemoryError
                    // because it may try to allocate exception objects.
                    if (waitForNotify) {
                        lock.wait();
                    }
                    // retry if waited
                    return waitForNotify;
                }
            }
        } catch (OutOfMemoryError x) {
            // Give other threads CPU time so they hopefully drop some live references
            // and GC reclaims some space.
            // Also prevent CPU intensive spinning in case 'r instanceof Cleaner' above
            // persistently throws OOME for some time...
            Thread.yield();
            // retry
            return true;
        } catch (InterruptedException x) {
            // retry
            return true;
        }

        // Fast path for cleaners
        if (c != null) {
            c.clean();
            return true;
        }

        ReferenceQueue<? super Object> q = r.queue;
        if (q != ReferenceQueue.NULL) q.enqueue(r); // 入队列
        return true;
    }





    static {
        ThreadGroup tg = Thread.currentThread().getThreadGroup();
        for (ThreadGroup tgn = tg;
             tgn != null;
             tg = tgn, tgn = tg.getParent());
        Thread handler = new ReferenceHandler(tg, "Reference Handler");
        /* If there were a special system-only priority greater than
         * MAX_PRIORITY, it would be used here
         */
        handler.setPriority(Thread.MAX_PRIORITY);
        handler.setDaemon(true);
        handler.start();

        // provide access in SharedSecrets
        SharedSecrets.setJavaLangRefAccess(new JavaLangRefAccess() {
            @Override
            public boolean tryHandlePendingReference() {
                return tryHandlePending(false);
            }
        });
    }



从源码中可以看出,这个线程在Reference类的static构造块中启动,并且被设置为最高优先级和daemon状态。此线程要做的事情就是不断的的检查pending是否为null,如果pending不为null,则将pending进行enqueue,否则线程进行wait状态。

    /**
     * Returns this reference object's referent.  If this reference object has
     * been cleared, either by the program or by the garbage collector, then
     * this method returns <code>null</code>.
     *
     * @return   The object to which this reference refers, or
     *           <code>null</code> if this reference object has been cleared
     */
    // 返回当前引用对象的指向的对象;如果对象已经被清除或被GC回收,返回NULL
    public T get() {
        return this.referent;
    }

    /**
     * Clears this reference object.  Invoking this method will not cause this
     * object to be enqueued.
     *
     * <p> This method is invoked only by Java code; when the garbage collector
     * clears references it does so directly, without invoking this method.
     */
    // 触发这个方法则不会进行入队的操作
    public void clear() {
        this.referent = null;
    }


    /* -- Queue operations -- */

    /**
     * Tells whether or not this reference object has been enqueued, either by
     * the program or by the garbage collector.  If this reference object was
     * not registered with a queue when it was created, then this method will
     * always return <code>false</code>.
     *
     * @return   <code>true</code> if and only if this reference object has
     *           been enqueued
     */
    // 判断对象是否已经入队
    public boolean isEnqueued() {
        return (this.queue == ReferenceQueue.ENQUEUED);
    }

    /**
     * Adds this reference object to the queue with which it is registered,
     * if any.
     *
     * <p> This method is invoked only by Java code; when the garbage collector
     * enqueues references it does so directly, without invoking this method.
     *
     * @return   <code>true</code> if this reference object was successfully
     *           enqueued; <code>false</code> if it was already enqueued or if
     *           it was not registered with a queue when it was created
     */
    // 入队操作
    public boolean enqueue() {
        return this.queue.enqueue(this);
    }



博文参考:
《Java源码分析》:ReferenceQueue、Reference及其子类
Java Reference 源码分析
  • 大小: 48.1 KB
分享到:
评论

相关推荐

    reference-ril.rar_android_android M 原生RIL库_reference-ril_ril-ref

    《Android M 原生RIL库:reference-ril详解》 在Android系统中,Radio Interface Layer(RIL)扮演着至关重要的角色,它是操作系统与无线调制解调器之间的桥梁,负责处理通信相关的任务,如语音通话、数据传输、...

    ANSYS Mechanical APDL Command Reference.pdf

    Welcome to the Command Reference.This reference contains a complete dictionary of detailed command descriptions, arranged in alphabetical order. It is the definitive resource for correct command ...

    PDF Reference 1.7_1.7_reference_信息_pdf1.7格式_pdf_

    标题中的"PDF Reference 1.7_1.7_reference_信息_pdf1.7格式_pdf_"表明我们将探讨的是关于PDF格式的1.7版本的官方参考指南。 PDF 1.7是PDF格式的一个重要里程碑,它被ISO标准化为ISO 32000-1,是目前许多PDF文档的...

    Find Reference 2 插件包

    "Find Reference 2 插件包"是一款专为大型项目设计的高效工具,它在Unity游戏开发环境中扮演着至关重要的角色。在处理复杂的项目时,往往会出现资源冗余,这不仅占用了大量的存储空间,还可能导致性能下降。该插件...

    SQL_reference.rar_SQL reference_reference sql

    SQL_Reference.rar 是一个关于SQL语言的参考资料,特别针对SQL Server这款流行的数据库管理系统。这个压缩包包含了一个名为"SQL_Reference.chm"的帮助文件,通常这种文件格式是Microsoft编写的帮助文档,方便用户...

    UVM_Class_Reference_Manual_1.2_UVM_Class_reference_uvm1.2_

    《UVM Class Reference Manual 1.2》是验证方法学(Unified Verification Methodology,简称UVM)中的核心文档,它详细介绍了UVM 1.2版本的类库及其使用方法。UVM是一种基于SystemVerilog的工业标准,用于硬件验证,...

    MySQL 5.6 Reference Manual MySQL 5.6 Reference Manual

    MySQL 5.6 Reference Manual MySQL 5.6 Reference Manual MySQL 5.6 Reference Manual MySQL 5.6 Reference Manual MySQL 5.6 Reference Manual MySQL 5.6 Reference Manual MySQL 5.6 Reference Manual ...

    MQL4 Reference.zip_MQL4帮助中文_MQL4帮助文件_MT4 帮助文件_mql4 reference_mt4

    《MQL4 Reference.zip》是一个压缩包,包含了MQL4的帮助文档,是学习和深入理解MQL4编程的重要资源。这个中文版的参考文件对于那些母语是中文的开发者来说尤其有帮助,因为它消除了语言障碍,使学习过程更加顺畅。 ...

    PDF Reference 1.6 中文版_去页眉

    《PDF Reference 1.6 中文版》是一个详尽的技术手册,为开发者提供了PDF 1.6版本的官方规范,涵盖了创建和处理PDF文档所需的技术细节。 在《PDF Reference 1.6 中文版》中,文档主要围绕以下几个方面展开详细讨论:...

    ANSYS Mechanical APDL Theory Reference.pdf

    《ANSYS Mechanical APDL理论参考》是ANSYS...总的来说,《ANSYS Mechanical APDL Theory Reference》是ANSYS用户深入理解和掌握APDL语言、提高仿真分析能力的重要资料,对于提升工程计算的精度和效率具有重要意义。

    PDF reference 1.6中文版

    总之,PDF Reference 1.6中文版和1.7英文版为读者提供了深入了解和操作PDF文档所需的知识,无论你是文档创建者、编辑者还是开发者,都能从中获益。结合PDF分析工具,你可以确保你的PDF文件符合标准,且能够被各种...

    abaqus scripting reference manual.pdf

    标题《Abaqus Scripting Reference Manual》和描述指出,本手册是Abaqus软件用于二次开发的脚本参考手册。标签“abaqus python”明确表明了手册内容与Python语言在Abaqus中的应用密切相关。手册是Abaqus ID发行的,...

    NASTRAN 2018帮助文档—quick reference guide.pdf

    NASTRAN的Quick Reference Guide是为用户提供快速查找NASTRAN软件中的关键字、命令和参数的参考文档。通过这份文档,用户可以快速地定位到所需的信息,从而有效利用NASTRAN的功能来解决具体的工程问题。 在这份...

    PDF Reference 1.7.pdf

    PDF Reference 1.7是PDF标准的一个重要版本,它详细定义了PDF 1.7规范,这个版本是PDF格式发展中的一个重要里程碑。 PDF 1.7规范包含了关于PDF文件结构、内容编码、图形和文本操作、表单处理、安全性、元数据等所有...

    c++ reference 最新版中文离线版20211231

    C++ Reference 是一个详尽的C++语言参考文档,为开发者提供了全面的语法、函数、类和概念介绍。 这个"20211231"版本的C++ Reference 中文离线版是为那些希望在没有网络连接的情况下查阅C++语言规范和库的程序员准备...

    pdf-reference1.7阅读注释版+pdf-reference1.6中文版+PDFSpy+xfa简介.zip

    首先,"pdf-reference1.7阅读注释版"是Adobe公司发布的PDF规范的第1.7版本,是PDF格式的官方指南。PDF 1.7标准定义了PDF的所有元素,包括文档结构、字体、图像、表单、安全和元数据等。这份文档通常对开发者来说具有...

    xilinx SDK : undefined reference to “xxx”

    直到查阅到类似情况:https://forums.xilinx.com/t5/Embedded-Development-Tools/SDK-undefined-reference/td-p/818300 发现我的工程的问题是gcc 链接时找不到库文件,如下图我在gcc链接命令中添加了 -llwip4 (该...

    CSS Quick Syntax Reference

    The CSS Quick Syntax Reference is a 150-page syntax reference to the Cascading Style Sheet specification and style sheet language. It presents the essentials of CSS in a well-organized format that can...

    Zynq-7000 Technical Reference Manual

    Zynq-7000是一款由Xilinx公司推出的All Programmable SoC(System on Chip,片上系统),其技术手册《Zynq-7000 All Programmable SoC Technical Reference Manual》为用户提供了深入的技术参考信息,以便用户能够...

    UIKit_Framework_Reference

    UIKit Framework Reference文档详细介绍了UIKit框架内的所有类和函数,对于iOS和tvOS开发者来说是核心参考资料之一。 在文档中,我们可以看到UIKit框架中包含了许多不同的类和模块,每个都有其特定的功能和用途。...

Global site tag (gtag.js) - Google Analytics