• 九、Android学习笔记_ Android开发中使用软引用和弱引用防止内存溢出


    复制代码
    在《Effective Java 2nd Edition》中,第6条“消除过期的对象引用”提到,虽然Java有 垃圾回收机制,但是只要是自己管理的内存,就应该警惕内存泄露的问题,例如的对象池、缓存中的过期对象都有可能引发内存泄露的问题。书中还提到可以用 WeakHashMap来作为缓存的容器可以有效解决这一问题。之前也确实遇到过类似问题,但是没有接触过“弱引用”相关的问题,于是查阅了一些资料。    《Java 理论与实践: 用弱引用堵住内存泄漏》一文也指出了使用全局的Map作为缓存容器时发生的内存泄露问题,介绍了如何使用hprof工具来找出内存泄露,并分析了如何使用 弱引用来防止内存泄露,还分析了WeakHashMap的关键代码,非常有参考价值。但是这篇文章遗漏了几个很重要的需要注意的地方,也缺少一段实验代 码,本文将会做出适当补充。
        1、四种引用
        从JDK1.2版本开始,把对象的引用分为四种级别,从而使程序能更加灵活的控制对象的生命周期。这四种级别由高到低依次为:强引用、软引用、弱引用和虚引用。
        强引用:平时我们编程的时候例如:Object object=new Object();那object就是一个强引用了。如果一个对象具有强引用,那就类似于必不可少的生活用品,垃圾回收器绝不会回收它。当内存空 间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
        软引用(SoftReference):如果一个对象只具有软引用,那就类似于可有可物的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存 空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存。 软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联 的引用队列中。
        弱引用(WeakReference):如果一个对象只具有弱引用,那就类似于可有可物的生活用品。弱引用与软引用的区别在于:只具有弱引用的对象拥有更 短暂的生命周期。在垃圾回收器线程扫描它 所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程, 因此不一定会很快发现那些只具有弱引用的对象。  弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联 的引用队列中。
        虚引用(PhantomReference):“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象 仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。 虚引用主要用来跟踪对象被垃圾回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。程序如果发现某个虚引用已经被加入到引用队 列,那么就可以在所引用的对象的内存被回收之前采取必要的行动。
    复制代码
    下面以使用软引用为例来详细说明。弱引用的使用方式与软引用是类似的。
    假设我们的应用会用到大量的默认图片,比如应用中有默认的头像,默认游戏图标等等,这些图片很多地方会用到。如果每次都去读取图片,由于读取文件需要硬件操作,速度较慢,会导致性能较低。所以我们考虑将图片缓存起来,需要的时候直接从内存中读取。但是,由于图片占用内存空间比较大,缓存很多图片需要很多的内存,就可能比较容易发生OutOfMemory异常。这时,我们可以考虑使用软引用技术来避免这个问题发生。
    首先定义一个HashMap,保存软引用对象。
    private Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();
     
    再来定义一个方法,保存Bitmap的软引用到HashMap。
        public void addBitmapToCache(String path) {
            // 强引用的Bitmap对象
            Bitmap bitmap = BitmapFactory.decodeFile(path);
            // 软引用的Bitmap对象
            SoftReference<Bitmap> softBitmap = new SoftReference<Bitmap>(bitmap);
            // 添加该对象到Map中使其缓存
            imageCache.put(path, softBitmap);
        }
     
     
        获取的时候,可以通过SoftReference的get()方法得到Bitmap对象。
        public Bitmap getBitmapByPath(String path) {
            // 从缓存中取软引用的Bitmap对象
            SoftReference<Bitmap> softBitmap = imageCache.get(path);
            // 判断是否存在软引用
            if (softBitmap == null) {
                return null;
            }
            // 取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
            Bitmap bitmap = softBitmap.get();
            return bitmap;
        }
     
    使用软引用以后,在OutOfMemory异常发生之前,这些缓存的图片资源的内存空间可以被释放掉的,从而避免内存达到上限,避免Crash发生。
    需要注意的是,在垃圾回收器对这个Java对象回收前,SoftReference类所提供的get方法会返回Java对象的强引用,一旦垃圾线程回收该Java对象之后,get方法将返回null。所以在获取软引用对象的代码中,一定要判断是否为null,以免出现NullPointerException异常导致应用崩溃。
     
    经验分享:
    到底什么时候使用软引用,什么时候使用弱引用呢?
    个人认为,如果只是想避免OutOfMemory异常的发生,则可以使用软引用。如果对于应用的性能更在意,想尽快回收一些占用内存比较大的对象,则可以使用弱引用。
    还有就是可以根据对象是否经常使用来判断。如果该对象可能会经常使用的,就尽量用软引用。如果该对象不被使用的可能性更大些,就可以用弱引用。
    另外,和弱引用功能类似的是WeakHashMap。WeakHashMap对于一个给定的键,其映射的存在并不阻止垃圾回收器对该键的回收,回收以后,其条目从映射中有效地移除。WeakHashMap使用ReferenceQueue实现的这种机制。
     
    复制代码
    Map<String, SoftReference<Bitmap>> iconCache=new HashMap<String, SoftReference<Bitmap>>();
    if (iconCache.containsKey(iconname)) {
    SoftReference<Bitmap> softref = iconCache.get(iconname);
    if (softref != null) {
       Bitmap bitmap = softref.get();
       if (bitmap != null) {
           iv_book.setImageBitmap(bitmap);
       } else {
           loadimage(iv_book, book, iconname);
       }
    
    }
    
    } else {
        loadimage(iv_book, book, iconname);
    }
    
    
    
    iconCache.put(iconname,new SoftReference<Bitmap>(bitmap));
    复制代码
  • 相关阅读:
    阿里云服务器常见问题记录
    npm 常见错误记录
    C程序设计(第四版)课后习题完整版 谭浩强编著
    博客如何快速让百度谷歌等各大引擎收录
    python itertools 用法
    python中dict的fromkeys用法
    python解析XML
    flask+uwsgi+nginx+docker-compose部署
    python的构建工具setup.py
    python判断字符串类型
  • 原文地址:https://www.cnblogs.com/liyuzhao/p/3783580.html
Copyright © 2020-2023  润新知