• 【Android】了解强引用、软引用、弱引用、虚引用


    【Android】了解强引用、软引用、弱引用、虚引用

    强引用(StrongReference)

    强引用是开发过程中最常用的引用方式,当一个对象具有强引用时,操作系统进行 GC 回收处理是不会回收强引用的对象,即使系统内存不足,

    Java虚拟机宁可抛 OutOfMemoryError(内存溢出错误),宁可使程序异常终止,也不会靠回收强引用的对象来解决内存不足的问题。

    只要把强引用对象 str 赋空值 null, 该对象就可以被 GC 垃圾回收器回收;因为该对象此时不再含有其他强引用。

    // 变量 str 表示强引用,指向 new String("codingce") 这个对象
    String str = new String("codingce"); 
    
    • 1
    • 2

    软引用(SoftReference)

    当JVM虚拟机内存充足时,软引用对象不会被 GC 垃圾回收器回收。

    当JVM虚拟机内存不足时,软引用对象会被 GC 垃圾回收器回收。

    未被回收的软引用对象是一直会被程序占有的。

    示例

     MySoftObj softObj = new MySoftObj();
     //软引用实例
     SoftReference softRef = new SoftReference(softObj);
     //获取软引用保存的引用
     MySoftObj anotherRef = (MySoftObj) softRef.get();
    
    • 1
    • 2
    • 3
    • 4
    • 5

    软引用可以和引用队列(ReferenceQueue)联合使用来实现内存紧张的高速缓存;如果软引用引用的对象被回收,Java虚拟机会把改软引用对象加到与之关联的引用队列中。

     MySoftObj softObj = new MySoftObj();
     ReferenceQueue queue = new  ReferenceQueue();
     SoftReference  softRef = new  SoftReference(softObj, queue);
    
    • 1
    • 2
    • 3

    例如: 对于处理图片这种占用内存大的逻辑,可以通过软引用缓存起来。但是在实践中,使用软引用作为缓存时效率是比较低的,系统并不知道哪些软引用指向的对象应该被回收,哪些应该被保留。过早被回收的对象会导致不必要的工作,比如 Bitmap 要重新从 SdCard 或者 网络上加载 到内存。在Android开发中,一种更好的选择是使用 LruCache

    弱引用(WeakReference)

    MyWeakObj weakObj = new MyWeakObj();
    //弱引用实例 
    WeakReference weakReference = new WeakReference<>(weakObj); 
    //获取弱引用保存的引用 
    MyWeakObj anotherRef = weakReference.get(); 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    对于弱引用对象,当操作系统进行 GC 回收处理时,不管内存空间是否足够,弱引用对象都会被回收。

    如果一个对象除了具有弱引用还具有强引用,GC回收时,该对象是不会被回收的,操作系统只会回收只具有弱引用的对象。

    弱引用常常被用于防止内存泄漏,最常见的是单例和Handler造成的内存泄漏。

    对于软引用场景举个很常用的例子:

    问题
    匿名内部类异步处理耗时逻辑且持有外部Activity强引用,当Activity被结束时,可能会出现因耗时导致匿名内部类在Activit结束后仍然未释放Activity对象,至Activity对象不能够被gc回收,进而引发内存泄漏问题。

    解决方案
    可以把 匿名内部类 写成一个静态类 比如叫 staticCallback,staticCallback 持有外部类的 弱引用。
    回调的时候判断下外部类还在不在,如果在就通知外部类更新,外部类不在就不用管。关键就是 callback 持有外部类的弱引用。匿名内部类都会隐式持有外部类的强引用,所以要把 callback 搞成一个静态类。

    代码

     /**
         * 将匿名内部类对象,定义成全局变量,
         * 这样 baseCallBack 的生命周期就和 外部Activity 一样
         */
        protected BaseCallBack baseCallBack;
    
        private void startLongTimeRequest() {
            baseCallBack = new BaseCallBack() {
                @Override
                public void onSuccess(String data) {
                    //执行业务逻辑
                }
            };
            //执行异步耗时请求
            CustomManager.getInstance().requestApi(new BaseCallBackWeak(baseCallBack));
        }
    
        static class BaseCallBackWeak implements BaseCallBack {
            private WeakReference<BaseCallBack> backWeakReference;
    
            public BaseCallBackWeak(BaseCallBack callback) {
                this.backWeakReference = new WeakReference<>(callback);
            }
    
            @Override
            public void onSuccess(String data) {
                //判断弱引用对象是否被回收
                if (backWeakReference != null && backWeakReference.get() != null) {
                    backWeakReference.get().onSuccess(data);
                }
            }
        }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    对弱引用的注意事项(目前的理解就是,最好的还是自行管理好对象的生命周期

    Memory leaks cannot be fixed by replacing strong references with weak references. It’s a common solution when attempting to quickly address memory issues, however it never works. The bugs that were causing references to be kept longer than necessary are still there. On top of that, it creates more bugs as some objects will now be garbage collected sooner than they should. It also makes the code much harder to maintain.

    虚引用(PhantomReference)

    虚引用不能保证其保存对象生命周期,若保存对象只有虚引用,则其有效期完全随机于GC的回收,在任何一个不确定的时间内,都可能会被回收;而虚引用与其他几者的引用不同在于,在使用PhantomReference,必须要和Reference联合使用。

    示例:

    MyPhantomObj phantomObj = new MyPhantomObj();
    //引用队列 
    ReferenceQueue queue = new ReferenceQueue<>(); 
    //虚引用 
    PhantomReference phantomReference = new PhantomReference(phantomObj, queue); 
    //获取虚引用保存的引用 
    MyPhantomObj anotherRef = phantomReference .get(); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
  • 相关阅读:
    Windows RDS远程会话服务
    ElementUI之动态树及书籍的分页查询
    新际遇?不看必后悔,成都市人民政府培育大企业大集团的实施意见
    在 IDEA 里下个五子棋不过分吧?
    yolo增加Inner-IoU,一文搞定(Inner-SIoU,Inner-WIoU,Inner-EIoU,Inner-MPDIoU)
    Java Web——JavaScript基础
    Java这些最基础的知识,你还记得多少?
    Android入门第33天-Android里的弹出式对话框
    英国访问学者|签证申请详细步骤简述
    MyBatis初级
  • 原文地址:https://blog.csdn.net/weixin_43874301/article/details/125888918