java引用类型

这里我贴几个比较好的链接,我的笔记也是基于它们的进行整合的

http://blog.youkuaiyun.com/as02446418/article/details/48025311
http://blog.youkuaiyun.com/qq_32795669/article/details/51292356

引用概念:

SoftReference、WeakReference、PhantomReference都是类java.lang.ref.Reference的子类。Reference作为抽象基类,定义了其子类对象的基本操作。Reference子类都具有如下特点:
1.Reference子类不能无参化直接创建,必须至少以强引用对象为构造参数,创建各自的子类对象;
2.因为1中以强引用对象为构造参数创建对象,因此,使得原本强引用所指向的堆内存中的对象将不再只与强引用本身直接关联,与Reference的子类对象的引用也有一定联系。且此种联系将可能影响到对象的垃圾回收。

一:java引用类型的分类

     * 1:强引用: 以new 一个对象的形式出现就是一个强引用的存在
     * 强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。
     * 当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。 ps:强引用其实也就是我们平时A a = new A()这个意思。
     * 2:软引用:在内存空间不足的时候才会去回收它【软引用可用来实现内存敏感的高速缓存】
     * 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
     * 3:弱引用:
        不管当前内存空间足够与否,在垃圾回收器线程扫描它所管辖的内存区域的过程,发现了弱引用就会回收它的内存, 弱引用也可以和一个引用队列(ReferenceQueue)联       合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
     * 4:虚引用:
     如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。 虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。
     
/**

* 二:引用类型的回收过程

* *【1】:软引用 * String abc=newString("abc"); //1 SoftReference<String> softRef=newSoftReference<String>(abc); * 更加上面代码分析软引用在应用内存不足的时候被gc回收的流程为 * 1:将SoftReference软引用类型的 softRef对象初始化构造函数中的abc对象设置为null,不在引用堆中的newString("abc")对象。 * 2:将堆中的new String("abc")对象设置为可结束的(finalizable). * 3:当heap中的new String("abc")对象的finalize()方法被运行而且该对象占用的内存被释放, softRef被添加到它的ReferenceQueue(如果softRef有添加到引用队列中的话)中。 【2】:虚引用 * String abc=newString("abc"); //1 SoftReference<String> softRef=newSoftReference<String>(abc); 1 不把referent设置为null, 直接把heap中的newString("abc")对象设置为可结束的(finalizable)。 2 与软引用和弱引用不同, 先把PhantomRefrence对象添加到它的ReferenceQueue中.然后在释放虚可及的对象。 */

三: 引用类型和引用队列结合以及通过引用队列进行清除无用引用类型对象的案例

//软引用虚引用和弱引用应尽量结合引用队列进行使用,这样可以避免因为创建多个引用类型的对象导致的内存泄露。在这些引用类型对象所指示的引用对象被回收的时候,那么他们的状态也是无用的,也是需要清理的,所以就通过引用队列来解决引用对象的内存; //具体清理代码如下【以清除无用的软引用类型对象为例】: //软引用结合引用队列进行使用 ReferenceQueue referenceQueue = new ReferenceQueue(); String abc = new String("abc"); //软引用保存abc的强引用,并和引用队列进行关联,abc对象回收的时候软引用对象softRef将被添加引用对象referenceQueue对象中。 SoftReference<String> softRef = new SoftReference<String>(abc, referenceQueue); //在引用类型指示的对象被回收的时候,也就是引用类型的对象,无用的情况下,需要进行回收引用类型对象,避免因为多个引用类型对象占据的内存所导致的内存泄露 SoftReference ref = null; while ((ref = (SoftReference) referenceQueue.poll()) != null) { // 清除无用的引用类型 ref.clear(); }

四:引用类型的使用场景:

   【1】:软引用的使用场景
        例:用Map集合缓存软引用的Bitmap对象
        Map<String, SoftReference<Bitmap>> imageCache = new new HashMap<String, SoftReference<Bitmap>>();
//强引用的Bitmap对象
        Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
//软引用的Bitmap对象
        SoftReference<Bitmap> bitmapcache = new SoftReference<Bitmap>(bitmap);
//添加该对象到Map中使其缓存
        imageCache.put("1",softRbitmap);
        ..
        .
//从缓存中取软引用的Bitmap对象
        SoftReference<Bitmap> bitmapCache = imageCache.get("1");
//取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
        Bitmap bm = bitmapCache .get();
利用软引用缓存图片到内存中,是安卓图片缓存的常用方法,它相对灵活,不会强占内存,容易回收。
【2】:弱引用

WeakReference不改变原有强引用对象的垃圾回收时机【值得是,只要弱引用被垃圾回收器给扫到了,就会被说是所指示的对象】,一旦其指示对象没有任何强引用对象时,此对象即进入正常的垃圾回收流程。

那么,依据此特点,很可能有疑问:WeakReference存在又有什么意义呢?

其主要使用场景见于:当前已有强引用指向强引用对象,此时由于业务需要,需要增加对此对象的引用,同时又不希望改变此引用的垃圾回收时机,此时WeakReference正好符合需求,常见于一些与生命周期的场景中。

下面给出一个Android中关于WeakReference使用的场景 —— 结合静态内部类和WeakReference来解决Activity中可能存在的Handler内存泄露问题。

Activity中我们需要新建一个线程获取数据,使用handler - sendMessage方式。

在Eclispe中Run Link,将会看到警示信息:This Handler class should be static or leaks might occur ...点击查看此信息,其详情中对问题进行了说明并给出了建议性的解决方案。

复制代码
Issue: Ensures that Handler classes do not hold on to a reference to an outer class
Id: HandlerLeak

Since this Handler is declared as an inner class, it may prevent the outer class from being garbage collected. If the Handler is using a Looper or MessageQueue for a thread other than the main thread, then there is no issue. If the Handler is using the Looper or MessageQueue of the main thread, you need to fix your Handler declaration, as follows: Declare the Handler as a static class;In the outer class, instantiate a WeakReference to the outer class and pass this object to your Handler when you instantiate the Handler; Make all references to members of the outer class using the WeakReference object.
复制代码

大致的意思是建议将Handler定义成内部静态类,并在此静态内部类中定义一个WeakReference的引用,由于指示外部的Activity对象。

问题分析:

Activity具有自身的生命周期,Activity中新开启的线程运行过程中,可能此时用户按下了Back键,或系统内存不足等希望回收此Activity,由于Activity中新起的线程并不会遵循Activity本身的什么周期,也就是说,当Activity执行了onDestroy,由于线程以及Handler 的HandleMessage的存在,使得系统本希望进行此Activity内存回收不能实现,因为非静态内部类中隐性的持有对外部类的引用,导致可能存在的内存泄露问题。

因此,在Activity中使用Handler时,一方面需要将其定义为静态内部类形式,这样可以使其与外部类(Activity)解耦,不再持有外部类的引用,同时由于Handler中的handlerMessage一般都会多少需要访问或修改Activity的属性,此时,需要在Handler内部定义指向此Activity的WeakReference,使其不会影响到Activity的内存回收同时,可以在正常情况下访问到Activity的属性。

 Google官方给出的建议写法为:

复制代码
 1 public class MainActivity extends Activity {
 2 
 3     //...
 4     private int page;
 5     private MyHandler mMyHandler = new MyHandler(this);
 6 
 7     private static class MyHandler extends Handler {
 8 
 9         private WeakReference<MainActivity> wrActivity;
10 
11         public MyHandler(MainActivity activity) {
12             this.wrActivity = new WeakReference<MainActivity>(activity);
13         }
14 
15         @Override
16         public void handleMessage(Message msg) {
17             if (wrActivity.get() == null) {
18                 return;
19             }
20             MainActivity mActivity = wrActivity.get();
21             if (msg.what == 1) {
22 
23                 //...
24                 mActivity.page++;
25 
26             } else {
27 
28                 //...
29 
30             }
31         }
32 
33     }
34 
35     @Override
36     protected void onCreate(Bundle savedInstanceState) {
37         super.onCreate(savedInstanceState);
38         setContentView(R.layout.activity_main);
39 
40         //...
41 
42         new Thread(new Runnable() {
43             @Override
44             public void run() {
45                 //.. 
46                 Message msg = Message.obtain();
47                 msg.what = 1;
48                 //msg.obj = xx;
49                 mMyHandler.sendMessage(msg);
50             }
51         }).start();
52 
53         //...
54 
55     }
56 
57 }
复制代码

五:引用类型的作用

1:软引用的作用: 被Soft Reference 指到的对象,即使没有任何 Direct Reference【直接引用】,也不会被清除。一直要到 JVM 内存不足且没有Direct Reference 时才会清除,SoftReference 是用来设计 object - cache 之用的。如此一来 SoftReference 不但可以把对象 cache 起来,也不会造成内存不足的错误(OutOfMemoryError)。 2:弱引用:
被弱引用指示的对象,弱引用不会改变指示对象的垃圾回收机制【指的是,只要弱引用的指示对象被垃圾回收器给扫到了,就会被回收
,一旦其指示对象没有任何强引用对象时,此对象即进入正常的垃圾回收流程。
使用例子为:
当前已有强引用指向强引用对象,此时由于业务需要,需要增加对此对象的引用,同时又不希望改变此引用的垃圾回收时机,此时WeakReference正好符合需求,常见于一些与生命周期的场景中,比如handler中需要activity的引用,但是又不希望改变activity的引用的垃圾回收机制,导致activity回收不了,出现内存溢出。
3:虚引用:在任何时候都有可能被回收,用于跟踪对象被垃圾回收的活动。虚引用和引用队列结合,在虚引用的引用对象被回收之前的时候,
添加到引用队列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。

六:总结

1:对于对象是属于哪种引用的对象,由它的最强的引用决定。 2:引用之间的区别:软引用和弱引用不强制必须要和引用队列(ReferenceQueue)进行结合使用,而虚引用需要强制要求和引用队列(ReferenceQueue)进行结合使用 3:软引用,弱引用,虚引用,和引用队列结合使用的话,可以在自身所引用的对象被回收时。 自身将被添加到引用队列中,此时自身处于无用对象状态,可以通过引用队列进行遍历清空自身对象。这样可以把对象依附的引用对象类型在不使用的时候也给回收掉,或者可以通过引用队列中获取引用类型或引用类型中保存的引用对象的信息。 4:引用队列,主要用于监听软引用,弱引用,虚引用的指示对象是否已经被回收,并进行相应处理、 5:软引用和弱引用是在对象被回收后添加到引用队列中的,而虚引用是在对象回收之前添加到引用对列的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值