完美告白,邯郸学步,标志508-呦吼福库,集福大本营

admin 3个月前 ( 07-15 05:23 ) 0条评论
摘要: super T˃ queue; /* When active: NULL * pending: this * Enqueued: next reference in queue...

原文:https://blog.csdn.net/gdutxiaoxu/article/details/80738581

从根底讲起

Reference

首要是担任内存的一个状况,当然它还和java虚拟机,废物收回器打交道。Reference类首先把内存分为4种状况Active,Pending,Enqueued,Inactive。

ReferenceQueue

引证行列,在检测到恰当的可抵达性更改后,废物收回器将已注册的引证目标增加到行列徐帅春中,ReferenceQueue完成了入队(enqueue)和出队(poll),还有remove操作,内部元素head便是泛型的Reference。

简略比如

当咱们想检测一个目标是否被收回了,那么咱们就能够选用 Reference + ReferenceQueue,大约需求几个过程:

创立一个引证行列 
ReferenceQueue queue = new ReferenceQueue();
// 创立弱引证,此刻状况为Active,而且Reference.pending为空,当时Reference.queue = 上面创立的queue,而且next=null
WeakReference reference = new WeakReference(new Object(), queue);
System.out.println(reference);
// 当GC履行后,由所以弱引证,所以收回该object目标,而且置于pending上,此刻reference的状况为PENDING
System.gc();
/* ReferenceHandler从pending中取下该元素,而且将该元素放入到queue中,此刻Reference状况为ENQUEUED,Reference.queue = ReferenceENQUEUED */
/* 当从queue里边取出该元素,则变为INACTIVE,Reference.queue = Referen完美表白,鹦鹉学舌,标志508-呦吼福库,集福大本营ce.NULL */
Reference reference1 = queue.remove();
System.out.println(reference1);

那这个能够用来干什么了?

能够用来检测内存走漏, github 上面 的 leekCanary 便是选用这种原理来检测的。


Refrence

首要内存成员变量

private T referent; 
volatile ReferenceQueue
/* When active: NULL
* pending: this
* Enqueued: next reference in queue (or this if last曲亭水库)
* Inactive: this
*/
@SuppressWarnings("rawtypes")
Reference next;
transient private Reference discovered; /* used by VM */
/* 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.
*/
private static Reference pending = null;

接下来,咱们来看一下 Refrence 的静态代码块

static {
ThreadGroup tg = Thread.currentThread().get完美表白,鹦鹉学舌,标志508-呦吼福库,集福大本营ThreadGroup();
for (ThreadGrouphotgirl tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread handler = new ReferenceHandler(tg, "Reference Handler");
完美表白,鹦鹉学舌,标志508-呦吼福库,集福大本营/* If th完美表白,鹦鹉学舌,标志508-呦吼福库,集福大本营ere 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);
}
});
}

咱们,当 Refrence 类被加载的时分,会履行静态代码块。在静态代码块里边,会发动 ReferenceHandler 线程,并设置线程的等级为最大等级, Thread.MAX_PRIORITY。

接下来咱们来看一下 ReferenceHandler 这个类,能够看到 run 办法里边是一个死循环,咱们首要重视 tryHandlePending 办法就 Ok 了

private static class Refer泰隆银行企业邮箱enceHandler extends Thread {
----- // 中心代码如下
public void run() {
while (true) {
tryHandlePending(true);
}
}
}
static boolean tryHandlePending(boolean waitForNotify) {
Reference r;
Cleaner c;
try {
synchronized (lock) {
// 查看 pending 是否为 null,不为 null,拟定 pending enqueue
if (pending != null) {
r = pending;
// 'instanceof' might throw OutOfMemoryError sometimes
// so do this before un-linking 'r' from the 'pending' chain..鄙陋侠.
c = r instanceof Cleaner ? (Cleaner) r : null;
// unlink 'r' from 'pending' chain
pending = r.discovered;
r.discovered = null;
} else { // 为 null。等候
// 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 ca完美表白,鹦鹉学舌,标志508-呦吼福库,集福大本营se 'r instanceof Cleane闲适158连锁酒店r' 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
if (q != ReferenceQueue.NULL) q.enqueue(r);
return tr阎超婕ue;
}

在 tryHandlePending 办法里边,查看 pending 是否为 null,假如pending不为 null,则将 pending 进行 还珠之天然呆是个萌物enqueue,不然线程进入 wait 状况。

问题马嘉诚和马嘉祺来了, 咱们从 Reference 源码中发现没有给 discovered和 pending 赋值的当地,那 pending和 discovered 到底是谁给他们赋值的。

咱们回头再来看一下注漠道难度释:简略来说,废物收回器会把 References 增加进入,Reference-handler thread 会移除它, 即 discovered和 pending 是由废物收回器进行赋值的

/* 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 lockmsmj object. The
* list uses the discovered field to link its elements.
*/
private static Reference pending = null;

RefrenceQueue

接下来,咱们在来看一下 RefrenceQueue 的 enqueue 办法

boolean enqueue(Reference
synchronized (lock) {
// Check that since getting the lock this reference hasn't already been
// enqueued (and eve好好僵尸女孩n then removed)
ReferenceQueue
// queue 为 null 或许 queue 现已被收回了,直接回来
if ((queue == NULL) || (queue == ENQUEUED)) {
return false;
}
assert queue == this;
// 将 refrence 的状况置为 Enqueued,表明现已被收回
r.queue = ENQUEUED;
// 接着,将 refrence 刺进到链表
// 判别当时链表是否为 null,不为 null,将 r.next 指向 head,为 null,head 直接指向 r
r.next = (head == null) ? r : head;
// head 指针指向 r
head = r;
queueLength++;
if (r instanceof FinalReference) {
sun.misc.VM.addFinalRefCount(1);
}
lock.notifyAll();
return true;
}
}

Refrence 和 RefrenceQueue 的源码剖析到此为止


Refrence 的子类

4种引证 咱们都知道在Java中有4种引证,这四种引证从高到低分别为: StrongReference

这个引证在Java中没有相应的类与之对应,可是强引证比较遍及,例如:Object obj = new Object();这儿的obj便是要给强引证,假如一个目标具有强引证,则废物收回器一直不会收回此目标。当内存缺乏时,JVM甘愿抛出OOM反常使薛守琴程序反常停止也不会靠收回强引证的目标来处理内存缺乏的问题。 SoftReference

假如一个目标只需软引证,则在内存足够的状况下是不会收回此目标的,可是,在内部缺乏即即将抛出OOM反常时就会收回此目标来处理内存缺乏的问题。

public class TestSoftReference {
private static ReferenceQueue rq = new ReferenceQueue();
public static void main(String[] args){
Object obj = new Object();
SoftReference sf = new SoftReference(obj,rq);
System.out.println(sf.get()!=null);
System.gc();
obj = null;
System.out.println(sf.get()!=null);
}
}

运转成果均为:true。

这也就阐明了当内存足够的时分一个目标只需软引证也不会被JVM收回。 WeakReference

WeakReference 根本与SoftRefer白雅雅ence 相似,仅仅收回仟易贷的战略不同。

只需 GC 发现一个目标只需弱引证,则就会收回此弱引证目标。可是由于GC地点的线程优先级比较低,不会当即发现一切弱引证目标并进行收回。只需GC对它所统辖的内存区域进行扫描时发现了弱引证目标就进行收回。

看一个比如:

public class TestWeakReference {
private static ReferenceQueue rq = new ReferenceQueue();
public static void main(String[] args) {
Object obj = new Object();
WeakReference wr = new WeakReference(obj,rq);
System.村庄小桃医out.println(wr.get()!=null);
obj = null;
System.gc();
System.out.println(wr.get()!=null);//false,这是由于WeakReference被收回
}
}

运转成果为: true 、false

在指向 obj = null 句子之前,Object目标有两条引证途径,其间一条为obj强引证类型,另一条为wr弱引证类型。此刻无论如何也不会进行废物收回。当履行了obj = null.Object 目标就只具有弱引证,而且咱们进行了显现的废物收回。因而此具有弱引证的目标就被GC给收回了。 PhantomReference

PhantomReference,即虚引证,虚引证并不会影响目标的生命周期。虚引证的作用为:盯梢废物收回器搜集目标这一活动的状况。

当GC一旦发现了虚引证目标,则会将PhantomReference目标刺进ReferenceQueue行列,而此刻PhantomReference目标并没有被废物收回器收回,而是要比及ReferenceQueue被你真实的处理后才会被收回。

留意:PhantomReference有必要要和ReferenceQueue联合运用,SoftReference和WeakReference能够挑选和ReferenceQueue联合运用也能够不挑选,这使他们的差异之一。

接下来看一个虚引证的比如。

public class TestPhantomReference {
private static ReferenceQueue rq = new ReferenceQ完美表白,鹦鹉学舌,标志508-呦吼福库,集福大本营ueue();
public static void main(String[] args){
Object obj = new Object();
PhantomReference pr = new PhantomReference(obj, rq);
System.out.println(pr.get());
obj = null;完美表白,鹦鹉学舌,标志508-呦吼福库,集福大本营
System.gc();
Sy性美国stem.out.println(pr.get());
Reference r = (Reference)rq.poll();
if(r!=null){
System.out.println("收回")dlidli;
}
}
}

运转成果:null null 收回

依据上面的比如有两点需求阐明:

总结

Refrence 和引证行列 ReferenceQueue 联合运用时,假如 Refrence持有的目标被废物收回,Java 虚拟机就会把这个弱引证加入到与之相关的引证行列中。

文章版权及转载声明:

作者:admin本文地址:http://www.fukuryouhousuu.com/articles/2450.html发布于 3个月前 ( 07-15 05:23 )
文章转载或复制请以超链接形式并注明出处呦吼福库,集福大本营