Java基础知识整理8:Java引用
使用
Java 中一共有 4 种类型的引用 :
- Strong Reference 强引用,Java的默认引用实现,会尽可能长时间的存活于JVM中,当没有对象引用时会在GC后被回收;
- Soft Reference 软引用,描述一些还有用但非必须的对象。在系统将要发生内存溢出异常之前,会将这些对象进行释放,直到JVM内存不足时才会被回收,如果还没有足够的内存,才会抛出溢出异常;
- Weak Reference 弱引用,描述非必须的对象,强度比软引用更弱一些,被若引用引用的对象下次GC就会回收
- Phantom Reference 虚引用,最弱的一种引用,一个对象是否有虚引用的存在,完全不会对其生存时间构成影响。唯一目的就是在这个对象被收集回收时受到一个系统通知。
相关的类
引用相关的类都在java.lang.ref下面,提供了引用对象类,支持在某种程度上与垃圾回收器之间的交互。程序中可以使用一个ref对象来维持对另外某一个对象的引用,
- Reference
- SoftReference
- WeakReference
- WeakHashMap
- PhantomReference
- ReferenceQueue
- FinalReference
- Finalizer
Reference类
Reference是一个抽象类,是引用对象的基类。该对象定义了所有引用对象的操作,引用对象是为了与垃圾回收器的密切合作而实现的,不能直接为此类创建子类。
- Reference中包含一个对象T,引用该ref对象引用的对象
- Reference有一个static的pending,GC会对其进行设置,该链表为GC设置的一个待GC,待入队列表
- Reference有一个ReferenceQueue和next,用于维护一个列表
public abstract class Reference<T>{
private T referent; //ref对象引用的对象
ReferenceQueue<? super T> queue; //见下面的分析
Reference next; //下一个,链表
transient private Reference<T> discovered; /* used by VM */
//GC用于同步的对象,在垃圾收集开始时,必须获得这个锁
//任务获得这个锁的对象都应该尽可能快的释放,不应该在持有期间内调用用户代码
static private class Lock { };
private static Lock lock = new Lock();
//等待入队的引用,垃圾收集器将引用添加到这个list
//Reference-handler线程会将pending移除并重新设置
//这个list被锁保护,dd
//静态的,reference使用
private static Reference pending = null;
//构造方法
Reference(T referent) {
this(referent, null);
}
Reference(T referent, ReferenceQueue<? super T> queue) {
this.referent = referent;
this.queue = (queue == null) ? ReferenceQueue.NULL : queue;
}
//返回ref对象引用的对象
public T get() {
return this.referent;
}
//清除引用对象,调用该方法不会导致排队
public void clear() {
this.referent = null;
}
//返回该对象是否被在排队
public boolean isEnqueued() {
synchronized (this) {
return (this.queue != ReferenceQueue.NULL) && (this.next != null);
}
}
//将ref对象添加到注册的队列中
//这个方法只会被java代码调用,垃圾回收器会直接将引用加入队列,无需调用此方法。
public boolean enqueue() {
return this.queue.enqueue(this);
}
}
Reference内部包含的一个ReferenceHandler线程,用来将pending引用入队列;由于该线程时static的,只会开一个
private static class ReferenceHandler extends Thread {
ReferenceHandler(ThreadGroup g, String name) {
super(g, name);
}
public void run() {
for (;;) { //无线循环
Reference r;
synchronized (lock) { //需要先获取lock
if (pending != null) {
r = pending;
Reference rn = r.next;
pending = (rn == r) ? null : rn;
r.next = r;
} else {
try {
lock.wait(); //pending为null 等待
} catch (InterruptedException x) { }
continue;
}
}
// Fast path for cleaners
if (r instanceof Cleaner) {
((Cleaner)r).clean();
continue;
}
ReferenceQueue q = r.queue;
if (q != ReferenceQueue.NULL) q.enqueue(r);
}
}
}
启动引用处理线程ReferenceHandler
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread handler = new ReferenceHandler(tg, "Reference Handler");
handler.setPriority(Thread.MAX_PRIORITY);//设置优先级为最高
handler.setDaemon(true);//守护线程
handler.start();//启动线程
}
ReferenceQueue类
ReferenceQueue类内部主要维护了链表的head和长度等信息,可以将pedding添加到队列中或移除
public class ReferenceQueue<T> {
public ReferenceQueue() { }
private static class Null extends ReferenceQueue {
boolean enqueue(Reference r) {
return false;
}
}
static ReferenceQueue NULL = new Null();
static ReferenceQueue ENQUEUED = new Null();
static private class Lock { };
private Lock lock = new Lock();
private volatile Reference<? extends T> head = null;
private long queueLength = 0;
boolean enqueue(Reference<? extends T> r) {
private Reference<? extends T> reallyPoll() {
public Reference<? extends T> poll() //
public Reference<? extends T> remove(long timeout)
public Reference<? extends T> remove()
}
SoftReference类
public class SoftReference<T> extends Reference<T> {
static private long clock; //时间戳锁,GC更新
private long timestamp; //调用get方法时更新,VM会使用该变量来清除但也不一定
//构造函数
public SoftReference(T referent) {
super(referent);
this.timestamp = clock;
}
//构造函数
public SoftReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
this.timestamp = clock;
}
//返回这个ref对象引用的对象,如果被清除了,会返回null
public T get() {
T o = super.get();
if (o != null && this.timestamp != clock)
this.timestamp = clock;
return o;
}
}
WeakReference类
public class WeakReference<T> extends Reference<T> {
public WeakReference(T referent) {
super(referent);
}
public WeakReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
PhantomReference类
public class PhantomReference<T> extends Reference<T> {
public T get() {
return null;
}
public PhantomReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
FinalReference类
class FinalReference<T> extends Reference<T> {
public FinalReference(T referent, ReferenceQueue<? super T> q) {
super(referent, q);
}
}
//final的类,package级别,不能被其他类调用和继承
final class Finalizer extends FinalReference {
//一个本地方法,调用一个任意对象的finalize方法,只要是protected的
static native void invokeFinalizeMethod(Object o) throws Throwable;
//ReferenceQueue 一个队列,静态的
static private ReferenceQueue queue = new ReferenceQueue();
static private Finalizer unfinalized = null;
static private Object lock = new Object();//锁
private Finalizer next = null,prev = null; //双向链表
//是否被调用了finalize方法
private boolean hasBeenFinalized() {
return (next == this);
}
//获得锁,加入链表中
private void add() {
synchronized (lock) {
if (unfinalized != null) {
this.next = unfinalized;
unfinalized.prev = this;
}
unfinalized = this;
}
}
//获得锁,从unfinalized链表中移除
private void remove() {
synchronized (lock) {
if (unfinalized == this) {
if (this.next != null) {
unfinalized = this.next;
} else {
unfinalized = this.prev;
}
}
if (this.next != null) {
this.next.prev = this.prev;
}
if (this.prev != null) {
this.prev.next = this.next;
}
this.next = this; /* Indicates that this has been finalized */
this.prev = this;
}
}
//构造方法,立即加入到队列
private Finalizer(Object finalizee) {
super(finalizee, queue);
add();
}
//VM虚拟机调用,创建一个Finalizer对象,引用finalizee
static void register(Object finalizee) {
new Finalizer(finalizee);
}
//运行引用指向对象的析构函数
private void runFinalizer() {
synchronized (this) {//如果已经被析构了,则返回,只会调用一次
if (hasBeenFinalized()) return;
remove();//从unfinalized链表移除,解除被链引用
}
try {
Object finalizee = this.get();//获取引用的对象,不为空且不为枚举则通过
//invokeFinalizeMethod原生方法调用finalizee的finalize方法(Object中定义)
if (finalizee != null && !(finalizee instanceof java.lang.Enum)) {
invokeFinalizeMethod(finalizee);
finalizee = null;//置为空
}
} catch (Throwable x) { }
super.clear();//不引用了 this.referent = null;
}
//创建一个线程
private static void forkSecondaryFinalizer(final Runnable proc) {
AccessController.doPrivileged(
new PrivilegedAction<Void>() {
public Void run() {
//创建线程
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread sft = new Thread(tg, proc, "Secondary finalizer");
sft.start();
try {
sft.join();
} catch (InterruptedException x) {
/* Ignore */
}
return null;
}});
}
//Runtime.runFinalization()调用,会启动线程,不断获取Finalizer,
//然后调用runFinalizer方法从而调用对象的finalize方法
static void runFinalization() {
forkSecondaryFinalizer(new Runnable() {
public void run() {
for (;;) {
Finalizer f = (Finalizer)queue.poll();
if (f == null) break;
f.runFinalizer();
}
}
});
}
/* Invoked by java.lang.Shutdown */
static void runAllFinalizers() {
forkSecondaryFinalizer(new Runnable() {
public void run() {
for (;;) {
Finalizer f;
synchronized (lock) {
f = unfinalized;
if (f == null) break;
unfinalized = f.next;
}
f.runFinalizer();
}}});
}
//Finalizer线程-1,queue中不断remove,然后调用runFinalizer方法
private static class FinalizerThread extends Thread {
FinalizerThread(ThreadGroup g) {
super(g, "Finalizer");
}
public void run() {
for (;;) {
try {
Finalizer f = (Finalizer)queue.remove();
f.runFinalizer();
} catch (InterruptedException x) {
continue;
}
}
}
}
static {
ThreadGroup tg = Thread.currentThread().getThreadGroup();
for (ThreadGroup tgn = tg;
tgn != null;
tg = tgn, tgn = tg.getParent());
Thread finalizer = new FinalizerThread(tg);
finalizer.setPriority(Thread.MAX_PRIORITY - 2);
finalizer.setDaemon(true);
finalizer.start();
}
}
- 注册:VM调用register方法,创建Finalizer,将该对象加入unfinalized链表;调用的时机有两个:先执行new分配好对象空间,然后再执行invokespecial调用构造函数,默认是构造函数返回之前调用Finalizer.register方法;如果通过-XX:-RegisterFinalizersAtInit关闭了该参数,那将在对象空间分配好之后将这个对象注册进去。
- 需要GC销毁的对象会从unfinalized链放入ReferenceQueue队列中,这样剥离了该对象在链上的引用,
- Finalizer线程-1,由static块启动,逻辑为:从queue中不断remove,然后调用runFinalizer方法
- Finalizer线程-2,由Shutdown方法调用runAllFinalizers启动,逻辑为:遍历unfinalized链表,然后调用runFinalizer方法
- Finalizer线程-2,由Runtime.runFinalization()调用启动,逻辑为:从queue中不断获取,然后调用runFinalizer方法
- runFinalizer方法:若Finalizer包装的对象不为空且不为枚举,则调用执行其finalize方法(Object中定义),然后从unfinalized链表移除(等待被GC回收);将包装对象设置为null;若已经调用过,则不会再调用finalize方法。
- GC时会将设置基类Reference中pending,后续将其加入到queue中,该queue是Finalizer的一个静态队列,保存了所有GC需要清理的强引用,后续调用runFinalizer方法,将从unfinalized链移除,引用置空。主要目的是清除引用,然后下次垃圾收集就会回收空间。
总结
- Java 引用 [http://san-yun.iteye.com/blog/1683558]
- ReferenceQueue的使用 [http://www.cnblogs.com/dreamroute/p/5029899.html]
- ThreadGroup
- FinalReference[http://www.infoq.com/cn/articles/jvm-source-code-analysis-finalreference/]
- ref包 [www.ibm.com/developerworks/cn/java/j-lo-langref/]
浙公网安备 33010602011771号