JAVA中四种引用类型详解
一、引用类型(referenceObject)
概述:java从1.2版本把对象的引用分为四种级别,由高到低分别为:强引用、软引用、弱饮用、虚引用。
目的:使程序能更加灵活的控制对象的生命周期,更高效地利用 Heap。
1. 强引用(StrongReference)
最普遍使用的引用。一个具有强引用的对象,绝不会被垃圾回收器回收。当内存不足时,应用程序会抛出OutOfMemoryError错误,使程序异常终止,也不会回收具有强引用的对象。
2. 软引用(SoftReference)
如果一个对象只具有软引用,当内存足够时,程序不会回收软引用对象;当内存不足时,会回收这些软引用对象的内存。
3. 弱引用(WeakReference)
如果一个对象只具有弱引用,当垃圾回收器进行回收时,无论内存是否充足,都会回收这些弱引用对象的内存。
4. 虚引用(PhantemReference)
如果一个对象只具有虚引用,则和没有引用一样,在任何时候都可能被垃圾回收器回收。
二、可及性(reachability)
1. 五种可及性
对象的引用状态会影响对象的可及性,可及性可以分为五种:
strongly reachable
An object is strongly reachable if it can be reached by some thread without traversing any reference objects. A newly-created object is strongly reachable by the thread that created it.
softly reachable
An object is softly reachable if it is not strongly reachable bu* can be reached by traversing a soft reference.
weakly reachable
An object is weakly reachable if it is neither strongly nor softly reachable but can be reached by traversing a weak reference. When the weak references to a weakly-reachable object are cleared, the object becomes eligible for finalization.
phantom reachable
An object is phantom reachable, if it is neither strongly, softly, nor weakly reachable, it has been finalized, and some phantom reference refers to it
unreachable
An object is unreachable, and therefore eligible for reclamation, when it is not reachable in any of the above ways.
2. 判断
在很多时候,一个对象并不是从根集直接引用的,而是一个对象被其他对象引用,甚至同时被几个对象所引用,从而构成一个以根集为顶的树形结构。从根集到一个对象可以由很多条路径,由此带来了一个问题,那就是某个对象的可及性如何判断:
- 单条引用路径可及性判断:在这条路径中,最弱的一个引用决定对象的可及性。
- 多条引用路径可及性判断:几条路径中,最强的一条的引用决定对象的可及性。
三、使用方式
1. 强引用
对象申请内存空间时,默认已经是强引用了。
Object obj =new Object(); // 强引用
2. 软引用
使用SoftReference类,为对象添加一个软引用。使用get方法获取原有对象的引用,如果原有对象已经被回收,则返回null值。
Objecy obj = new Object();
SoftReference sfRefer = new SoftReference (obj);//为obj添加一个软引用
sfRefer.get();//获得原有对象引用
3. 弱引用
使用WeakReference类,为对象添加一个弱引用。使用方法和软引用类似。
Objecy obj = new Object();
WeakReference wfRefer = new WeakReference (obj);//为obj添加一个弱引用
wfRefer.get();//获得原有对象引用
4. 虚引用
使用PhantemReference类,为对象添加一个虚引用。必须与ReferenceQueue配合使用。不能通过PhantemReference获取原有对象引用,get方法永远返回null。
ReferenceQueue queue = new ReferenceQueue();
PhantomReference ref = new PhantomReference(new Object(), queue);
5. 引用队列(ReferenceQueue)
目的:监测引用的引用对象的回收情况,便于在对象被回收后进行进一步处理。
使用:和SoftReference、WeakReference、PhantemReference配合使用。如果引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个引用加入到与之关联的引用队列中。
Object object = new Object();
ReferenceQueue queue = new ReferenceQueue();
WeakReference wfRefer = new WeakReference(object, queue); //添加虚引用,并设置相关引用队列
object = null; //确保object只有一个虚引用
System.gc(); //触发垃圾回收,或者主动调用System.gc()
Thread.sleep(2000);
Reference ref = null;
while((ref = queue.poll())!=null){
if(ref == wfRefer){
System.out.println("object has reclaimed"); //后续处理
}
}
四、Android环境的特殊性
google不建议在android环境中使用SoftReference
The lack of information on the value to your application of each reference limits the usefulness of soft references. References that are cleared too early cause unnecessary work; those that are cleared too late waste memory.
对于Android系统来说,对于内存较为敏感,对于内存释放也更加严格。 SoftReference 无法提供足够的信息可以让 系统很轻松地决定clear它还是keep它。
五、实际应用(Android)
1. 缓存
在应用开发过程中,有时候会经常访问数据缓存起来,减少读取数据的时间消耗,同时不希望这些数据影响到正常的内存回收。可以使用WeakRefercence来引用这些对象。可以使用WeakHashMap或者搭配LruCache使用。
2. Handler
为了避免Memory Leak,我们会定义一个内部静态类,然后以 WeakReference 的形式引用 Activity,使队列中的 Message (可能会排队很长时间)不会干扰到 Activity的正常回收。
public class MainActivity extends Activity {
private static final int MSG_ID = 0x00;
public void testSafeHandler() {
SafeHandler handler = new SafeHandler(this);
handler.sendEmptyMessage(MSG_ID);
}
public static class SafeHandler extends Handler {
private WeakReference<Activity> mActivityRef;
public SafeHandler(Activity activity) {
mActivityRef = new WeakReference<>(activity);
}
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_ID:
Activity activity = mActivityRef.get();
if (activity != null) {
activity.finish();
}
}
}
}
}