Java Reference & ReferenceQueue一览

Overview

The java.lang.ref package provides more flexible types of references than are otherwise available, permitting limited interaction between the application and the Java Virtual Machine (JVM) garbage collector. It is an important package, central enough to the language for the language designers to give it a name that starts with "java.lang", but it is somewhat special-purpose and not used by a lot of developers. This package was added in J2SE 1.2.

Java has an expressive system of references and allows for special behavior for garbage collection. A normal reference in Java is known as a "strong reference." The java.lang.ref package defines three other types of references — soft, weak, and phantom references. Each type of reference is designed for a specific use.

 

Reference in JAVA

Base

Strong Reference,强引用,即java标准的引用方式,表示GC从 Root Set 开始向下扫描,可以找到对应的 Strong Reference。
FinalReference 作为 java.lang.ref 里的一个不能被公开访问的类,实际上,FinalReference 代表的正是 Java 中的强引用。

Referent,被包装为 Weak, Soft, Phantom Reference的对象引用称之为 referent。

Soft Reference ,软引用。它是除strong外,生命周期最长的一种 Reference,只有当JVM Heap中充满Strong References,
Full GC无法为heap腾出更多空间而即将抛出OOM时,SoftReferences会被GC回收。

Weak Reference,弱引用。当一个referent,在运行时没有同时被强,软引用,只被Weak Reference自身引用,且Weak Reference
从 Root Set 可达,则该referent会被GC回收。

WR的作用,一般是为referent提供一个被回收的凭据,结合ReferenceQueue可以让程序在第一时间得到referent被回收的事件,
从而做一些额外的clean操作。

Phanton Reference, 是一种特殊的Reference,正如他的名字所表达的,幻影引用,他可以像幻影一样附着在referent上。
当GC在遍历引用关系时,如果发现被phantom reference包装过的referent不存在strong, weak, soft引用时(就是除phantom外
没有任何引用,幻影的由来),GC会将 phantom reference 放入 Reference queue。以便程序在另一边通过queue的remove/poll
方法,感知referent被GC回收的事件。

feature

Soft Reference Keeps objects alive provided there’s enough memory. to keep objects alive even after clients have removed their references (memory-sensitive caches), in case clients start asking for them again by key. After a first gc pass, the JVMdecides it still needs to reclaim more space. java.lang.ref.SoftReference
Weak Reference Keeps objects alive only while they’re in use (reachable) by clients. Containers that automatically delete objects no longer in use. After gc determines the object is only weakly reachable java.lang.ref.WeakReference
java.util.WeakHashMap
Phantom Reference Lets you clean up after finalization but before the space is reclaimed (replaces or augments the use offinalize()) Special clean up processing After finalization. java.lang.ref.PhantomReference

important

按理说,Soft Reference 与 Weak Reference都可以用来实现缓存,只是失效策略不同,一个是内存不足时清理,一个是随意清理

另外WeakHashMap并不适用于缓存,详见weakHashMap解析

Overview the relationship between Reference&ReferenceQueue

ReferenceQueue是作为 JVM GC与上层Reference对象管理之间的一个消息传递方式,允许注册一些监听器来获取回收状态

Java Reference & ReferenceQueue一览_第1张图片

class#java.lang.ref.Reference

reference objects are implemented in close cooperation with the garbage collector

Overview

 1  /* A Reference instance is in one of four possible internal states:
 2        一个Reference实例有以下4种内部状态
 3      *
 4      *       Active: Subject to special treatment by the garbage collector.  Some
 5      *       time after the collector detects that the reachability of the
 6      *       referent has changed to the appropriate state, it changes the
 7      *       instance's state to either Pending or Inactive, depending upon
 8      *       whether or not the instance was registered with a queue when it was
 9      *       created.  In the former case it also adds the instance to the
10      *       pending-Reference list.  Newly-created instances are Active.
11      *       当垃圾回收器探测到引用的可达性变成某些适合的状态的时候,
12      *       它会将该内部状态变成Pending或者Inactive,
13      *       这取决于在实例化这个Reference对象的时候是否传入了ReferenceQueue。
14      *     如果传入了,那么它同时会将该实例添加到pending-Reference列表中。
15      *     新创建的引用对象是Active
16      *
17      *       Pending: An element of the pending-Reference list, waiting to be
18      *       enqueued by the Reference-handler thread.  Unregistered instances
19      *       are never in this state.
20      *       一个在Pend-Reference列表中的元素,正等待着Reference-handler线程将他入队。
21      *       未注册的实例不会出现在这个状态。
22      *
23      *       Enqueued: An element of the queue with which the instance was
24      *       registered when it was created.  When an instance is removed from
25      *       its ReferenceQueue, it is made Inactive.  Unregistered instances are
26      *       never in this state.
27      *       当一个实例从它的ReferenceQueue中被删除时,它变成Inactive状态。
28      *       未注册的instance不会
29      *
30      *       Inactive: Nothing more to do.  Once an instance becomes Inactive its
31      *       state will never change again.
32      *       不会再做任何改变。一旦某个实例变成了Inactive态,它的状态不会再有任何改变。
33      *
34      * The state is encoded in the queue and next fields as follows:
35      *
36      *       Active: queue = ReferenceQueue with which instance is registered, or
37      *       ReferenceQueue.NULL if it was not registered with a queue; next =
38      *       null.
39      *
40      *       Pending: queue = ReferenceQueue with which instance is registered;
41      *       next = Following instance in queue, or this if at end of list.
42      *
43      *       Enqueued: queue = ReferenceQueue.ENQUEUED; next = Following instance
44      *       in queue, or this if at end of list.
45      *
46      *       Inactive: queue = ReferenceQueue.NULL; next = this.
47      *
48      * With this scheme the collector need only examine the next field in order
49      * to determine whether a Reference instance requires special treatment: If
50      * the next field is null then the instance is active; if it is non-null,
51      * then the collector should treat the instance normally.
52      *
53      * 以这种方式,收集器只需要检查next字段,以决定是否该引用实例应该被特殊处理
54      * 如果下一个字段是null,说明该实例为active
55      * 如果不是null,说明回收器应该立刻处理该实例
56      *
57      * To ensure that concurrent collector can discover active Reference
58      * objects without interfering with application threads that may apply
59      * the enqueue() method to those objects, collectors should link
60      * discovered objects through the discovered field.
61      *
62      * 为了保证并发收集器可以再不受应用程序线程调用enqueue()发放的影响下,发现active reference
63      * 收集器应该吧已经发现的objects通过discovered 字段表示。
64      *
65      */

Inner Field 非static

T referent

Treated specially by GC

是该引用实例真正指向的对象,为了避免和reference同名,名字叫做referent

ReferenceQueue<? super T> queue
引用队列,通知队列(使用方法具体见后文)

Reference next
链表指针,是GC里面的pending list

Reference<T> discovered

used by VM

 

Global Field ,static

Lock lock
一个空对象,用于锁同步
     /* 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.
     * 这是垃圾回收器用来同步的对象。在垃圾回收周期之前,回收器需要获取这个锁。
     * 因此,任何持有该锁的对象应该尽快执行完,尽量不要分配新对象,避免调用用户代码
     */

Reference<T> pending

所谓的pending链表,依赖于reference的next指针实现,大部分对于该链表的操作都是通过vm执行

ReferenceHandler#Class

implement Runable

监听(wait/notify)pending链表,通过将pending链表的元素enque来实现监视器模式,以便回调各个reference注
册的queue上面的的监听者(调用remove或者poll方法)

 1   for (;;) {
 2 
 3                 Reference r;
 4                 synchronized (lock) {
 5                     if (pending != null) {
 6                         //删除pending列表的该对象
 7                         r = pending;
 8                         Reference rn = r.next;
 9                         pending = (rn == r) ? null : rn;
10                         r.next = r;
11                     } else {
12                         try {
13                             lock.wait(); //该wait由VM来notify
14                         } catch (InterruptedException x) { }
15                         continue;
16                     }
17                 }
18 
19                 // Fast path for cleaners
20                 // 钩子
21                 if (r instanceof Cleaner) {
22                     ((Cleaner)r).clean();
23                     continue;
24                 }
25 
26                 ReferenceQueue q = r.queue;
27                 //将该对象入队
28                 //加入ReferenceQueue中的链表中,见下文
29                 if (q != ReferenceQueue.NULL) q.enqueue(r);
30             }

static块

启动ReferenceHandler 设置为最高优先级并且为守护进程

Interface

Reference(T referent)

默认构造器

Reference(T referent, ReferenceQueue<? super T> queue)

带有ReferenceQueue的构造器

T get()

获取该referent

void clear()

清空

boolean isEnqueued()

是否入队,根据queue和next指针来判断

boolean enqueue()

入队方法,VM不会调用该方法,暂时不知道谁来调用

class#java.lang.ref.ReferenceQueue

Overview

Reference queues, to which registered reference objects are appended by the
garbage collector after the appropriate reachability changes are detected.

引用队列,将Reference Object注册到该队列上,使得当垃圾回收器改变其到某些状态的时候能够被探测到。

总之,这是一个观察引用对象回收的东西

通过wait/notify实现的阻塞和非阻塞调用~ 

该操作涉及一些并发知识哦~

Inner Field

//队列头
volatile Reference<? extends T> head = null;

//队列长度
long queueLength = 0;

Interface

enqueue

Called only by Reference Class

调用入队操作,删除元素的对该队列的引用,将元素插入头,增加长度,lock.notify

remove

阻塞调用(lock.wait),获取一个元素。

poll

非阻塞调用。

基于Reference和ReferenceQueue实现的WeakHashMap

详见:WeakHashMap, Not a cache

REFERENCE

  1. 深入探讨 java.lang.ref 包@IBMer
  2. 话说ReferenceQueue
  3. Java Reference概念整理
  4. 深入理解ReferenceQueue GC finalize Reference
  5. 深入理解java的finalize
  6. Understanding Weak References

 

你可能感兴趣的:(Java Reference & ReferenceQueue一览)