Java/Android中的强引用、软引用、弱引用、虚引用

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

  • 引用类型

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

强引用

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

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

特点:

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

软引用

    A a = new  A();
    SoftReference aSoftRef=new SoftReference(a);

    A a1=(A)a.get();

一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。
只要垃圾回收器没有回收它,该对象就可以被程序使用。

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

    ReferenceQueue queue = new  ReferenceQueue();
    SoftReference  softReference=new  SoftReference(软引用对象, queue);

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是否为空,负责将会出现空指针异常.

  • 案例2

设计给出了一张1080的全屏图片,这张图片假设500K,可以想象它的内存消耗,通用使用软引用来解决

public class SoftReferenceActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ImageView imageView=new ImageView(this);
        BitmapFactory.Options options=new BitmapFactory.Options();
        options.inPreferredConfig= Bitmap.Config.ARGB_4444;
        options.inPurgeable= true;
        options.inInputShareable= true;
        options.outWidth= 720;
        options.outHeight= 1280;
        Bitmap bitmap=BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher_round,options);
        Drawable drawable=new BitmapDrawable(getResources(),bitmap);
        SoftReference<Drawable> drawableSoftReference =
                new SoftReference<Drawable>(drawable);
        if(drawableSoftReference != null) {
            //内存不足将不显示
            imageView.setBackground(drawableSoftReference.get());
        }

    }
}

因此在特定的场景想要避免OOM的发生就尽量使用软引用吧.

但是在Android中最好选择Least Recently Used(LRU),在它内部维护一个特定大小内存,在内存不足时会根据一系列的策略算法来进行处理移除掉当前一些缓存以便获取新的内存空间用来缓存数据.

弱引用

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

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

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

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

Android中的示例

在最常见的Handler持有一个Activity的引用,Handler作为一个耗时的异步线程处理,如果在处理过程中把Activity关闭了,因为Handler还持有Activity的引用,而一个异步线程持有Handler引用,那么就将导致内存泄漏

解决方案:

  • 在Activity关闭的地方将线程停止以及把Handler的消息队列的所有消息对象移除
  • Handler改为静态类

这里我们使用将Handler改为静态类,但是因为静态类无法持有外部引用,就需要建立一个队Activity的弱引用了

public class WeakReferenceActivity extends AppCompatActivity {

    private WeakReference<WeakReferenceActivity> reference;
    private MyHandler myHandler = new MyHandler(this);

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        myHandler.sendEmptyMessage(1);
    }


    public static class MyHandler extends Handler {
        private WeakReference<WeakReferenceActivity> reference;

        public MyHandler(WeakReferenceActivity activity) {
            reference = new WeakReference<WeakReferenceActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case 1:
                    WeakReferenceActivity weakReferenceActivity = (WeakReferenceActivity) reference.get();
                    if (weakReferenceActivity != null) {
                        System.out.print("WeakReferenceActivity");
                    }
                    break;

                default:
                    break;
            }
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        myHandler.removeCallbacksAndMessages(null);
    }
}

虚引用

在对象销毁时会被回收.

在Java中GC的运行时间是不确定的,在Java里有一个finalize方法,在垃圾回收器准备释放内存的时候,会先调用finalize().但因为内存还没有好耗尽,拟机不能保证在适当的时机调用finalize,因此垃圾回收期与finalize是不可靠的方法.

这时可以采用虚引用.比如一个固定的内存,在明确知道一个bitmap回收之后会释放一部分内存,新释放开辟的内存就可以让其他bitmap来使用,以此循环来达到内存的稳定性控制.

总结

在Android中比较常用便是 弱引用软引用了。

对于一些OOM等常规处理使用软引用便可很好的解决,可以实现高速缓存.

对于偶尔使用的对象,并且随时获取到便使用弱引用来标记

软引用与弱引用的区别:只含有弱引用的对象的生命周期更短。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。

虚引用只要用于内存的精准控制,如Android中的ViewPager图片的查看等等

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容