强引用-软引用-弱引用-虚引用.

引用分为四个,从高到低的级别以此为强引用-软引用-弱引用-虚引用.

  • 引用类型

    类别回收机制用途生存时间
    强引用从不回收对象状态JVM停止运行时
    软引用内存不足时进行回收缓存内存不足
    弱引用对象不被引用时回收缓存GC运行后
    虚引用对象被回收时管理控制精确内存稳定性unknown

强引用

Qiang qiang=new Qiang();
Niu niu=new Niu(qiang)

强引用例子,niu持有qiang的引用,当qiang=null的时候,并不能回收,而niu需要qiang,导致内存泄漏,典型的引用泄漏.

特点:

  • 即便OOM也不会发生回收.
  • 强引用在引用对象null时会导致内存泄漏
  • 强引用可以直接访问目标对象

Android中的示例

案例1:

在平常Android开发中,有很多的图片要显示,如果是网络的则通过网络解析获取,如果
每次都从网络解析影响体验,那么我们会将其保存到本地,如果每次从本地获取相对于我们将获取后的图片缓存下来直接从内
存中获取效率更低.但是因为图片的数量多,消耗内存过大,缓存图片的过程需要大量的内存,内存不够则会OOM,这时便可以采用软引用的技术来解决问题.

 private Map<String,SoftReference> softReferenceMap=new HashMap<>();


    /**
     *
     * @param path
     */
    public  void addBitmap(String path){
        // 强引用的Bitmap对象
        Bitmap bitmap = BitmapFactory.decodeFile(path);
        // 软引用的Bitmap对象
        SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
        // 添加softBitmap到Map中使其缓存
        softReferenceMap.put(path, softBitmap);
    }

    /**
     *
     * @param path
     * @return
     */
    public Bitmap getBitmap(String path) {
        // 从缓存中取软引用的Bitmap对象
        SoftReference<Bitmap> softBitmap = softReferenceMap.get(path);
        // 判断是否存在软引用
        if (softBitmap == null) {
            return null;
        }
        // 取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
        Bitmap bitmap = softBitmap.get();
        return bitmap;
    }

在softBitmap.get()中获取Bitmap的实例的强引用,在内存充足的情况下不会回收软引用对象,可以取出bitmap

内存不足时,softBitmap.get()不在返回bitamp直接返回null,软引用被回收了

因此在获取Bitmap的对象之前要判断softBitmap == null是否为空,负责将会出现空指针异常.

弱引用

 WeakReference<MainActivity> weakReference = new WeakReference<MainActivity>(new MainActivity()) ;

如果一个对象只具有弱引用,那么在垃圾回收器线程扫描的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存.

不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。

2. ReferenceQueue(引用队列)简介

当gc(垃圾回收线程)准备回收一个对象时,如果发现它还仅有软引用(或弱引用,或虚引用)指向它,就会在回收该对象之前,把这个软引用(或弱引用,或虚引用)加入到与之关联的引用队列(ReferenceQueue)中。如果一个软引用(或弱引用,或虚引用)对象本身在引用队列中,就说明该引用对象所指向的对象被回收了。

当软引用(或弱引用,或虚引用)对象所指向的对象被回收了,那么这个引用对象本身就没有价值了,如果程序中存在大量的这类对象(注意,我们创建的软引用、弱引用、虚引用对象本身是个强引用,不会自动被gc回收),就会浪费内存。因此我们这就可以手动回收位于引用队列中的引用对象本身。

除了上面代码展示的创建引用对象的方式。软、弱、虚引用的创建还有另一种方式,即在创建引用的同时关联一个引用队列。

ReferenceQueue的使用

对于软引用弱引用,我们希望当一个对象被gc掉的时候通知用户线程,进行额外的处理时,就需要使用引用队列了。ReferenceQueue即这样的一个对象,当一个obj被gc掉之后,其相应的包装类,即ref对象会被放入queue中。我们可以从queue中获取到相应的对象信息,同时进行额外的处理。比如反向操作,数据清理等。

package reference;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by haicheng.lhc on 11/05/2017.
 *
 * @author haicheng.lhc
 * @date 2017/05/11
 */
public class RefTest {

    private static ReferenceQueue<byte[]> rq = new ReferenceQueue<byte[]>();
    private static int _1M = 1024*1024;

    public static void main(String[] args) {
        Object value = new Object();
        Map<Object, Object> map = new HashMap<>();
        Thread thread = new Thread(() -> {
            try {
                int cnt = 0;
                WeakReference<byte[]> k;
                while((k = (WeakReference) rq.remove()) != null) {
                    System.out.println((cnt++) + "回收了:" + k);
                }
            } catch(InterruptedException e) {
                //结束循环
            }
        });
        thread.setDaemon(true);
        thread.start();

        for(int i = 0;i < 10000;i++) {
            byte[] bytes = new byte[_1M];
            WeakReference<byte[]> weakReference = new WeakReference<byte[]>(bytes, rq);
            map.put(weakReference, value);
        }
        System.out.println("map.size->" + map.size());
    }
}

输出结果是:

...
9803回收了:java.lang.ref.WeakReference@702c436b
9804回收了:java.lang.ref.WeakReference@1744a475
9805回收了:java.lang.ref.WeakReference@213bd3d5
map.size->10000

结果分析

因为map的key是WeakReference,所以在内存不足的时候,weakReference所指向的对象就会被GC,在对象被GC的同时,会把该对象的包装类即weakReference放入到ReferenceQueue里面。但是这个map的大小是10000.

PS

上面的reference换成SoftReference,结果一样。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值