美文网首页
WeakReference 弱引用与内存泄漏

WeakReference 弱引用与内存泄漏

作者: 小面包屑 | 来源:发表于2017-03-08 16:58 被阅读0次
    compile 'com.anthonycr.grant:permissions:1.1.2'
    

    版本更新后,作者为了避免内存泄漏,在源码中添加了一个弱引用来存储一个抽象类。

    但在用户有多个权限需要选择的时候,抽象类有时候会被回收。当用户确认权限之后,没有调用到回调函数。

    android内存空间分配

    首先, 让我们快速看下Android启动流程. 与众多基于Linux内核的系统类似, 启动系统时, bootloader启动内核和init进程. init进程分裂出更多名为"daemons(守护进程)"的底层的Linux进程, 诸如android debug deamon, USB deamon等. 这些守护进程处理底层硬件相关的接口.

    随后, init进程会启动一个非常有意思的进程---"Zygote". 顾名思义, 这是一个Android平台的非常基础的进程. 这个进程初始化了第一个VM, 并且预加载了framework和众多App所需要的通用资源. 然后它开启一个Socket接口来监听请求, 根据请求孵化出新的VM来管理新的App进程. 一旦收到新的请求, Zygote会基于自身预先加载的VM来孵化出一个新的VM创建一个新的进程.

    启动Zygote之后, init进程会启动runtime进程. Zygote会孵化出一个超级管理进程---System Server. SystemServer会启动所有系统核心服务, 例如Activity Manager Service, 硬件相关的Service等. 到此, 系统准备好启动它的第一个App进程---Home进程了.

    app launch

    当启动一个Android程序时,会启动一个Dalvik VM进程,系统会给它分配固定的内存空间(16M,32M不定),这块内存空间会映射到RAM上某个区域。然后这个Android程序就会运行在这块空间上。Java里会将这块空间分成Stack栈内存和Heap堆内存。stack里存放对象的引用,heap里存放实际对象数据。
    在程序运行中会创建对象,如果未合理管理内存,比如不及时回收无效空间就会造成内存泄露,严重的话可能导致使用内存超过系统分配内存,即内存溢出OOM,导致程序卡顿甚至直接退出。

    dalvik的Heap和Stack

    也就是带有回调函数的对象会放到内存堆中。当然,一般处理内存泄漏都是处理内存堆,这里只是提一下。

    弱引用

    在Java里, 当一个对象o被创建时, 它被放在Heap里. 当GC运行的时候, 如果发现没有任何引用指向o, o就会被回收以腾出内存空间. 或者换句话说, 一个对象被回收, 必须满足两个条件: 1)没有任何引用指向它 2)GC被运行

       private synchronized void addPendingAction(@NonNull String[] permissions,
                                                   @Nullable PermissionsResultAction action) {
            if (action == null) {
                return;
            }
            action.registerPermissions(permissions);
            mPendingActions.add(new WeakReference<>(action));
        }
    
        public synchronized void notifyPermissionsChange(@NonNull String[] permissions, @NonNull int[] results) {
            int size = permissions.length;
            if (results.length < size) {
                size = results.length;
            }
            Iterator<WeakReference<PermissionsResultAction>> iterator = mPendingActions.iterator();
            while (iterator.hasNext()) {
                PermissionsResultAction action = iterator.next().get();
                for (int n = 0; n < size; n++) {
                    if (action == null || action.onResult(permissions[n], results[n])) {
                        iterator.remove();
                        break;
                    }
                }
            }
            for (int n = 0; n < size; n++) {
                mPendingRequests.remove(permissions[n]);
            }
        }
    

    在源码中执行到这儿的时候,action有时候变成了null 。

    在addPendingAction操作中有PermissionsResultAction(强引用)引用指向,但到notifyPermissionsChange()的时候PermissionsResultAction依然被系统回收了,回调函数不被执行。

    这是因为编译器在发现进入while循环之后, PermissionsResultAction已经没有被使用, 所以进行了优化(将其置空).

    写了一段测试代码,对象最后的确被回收了。

      public static void main(String[] args) {
    
            List<WeakReference<PermissionAction>> mPendingActions = new ArrayList<>(1);
    
    
            mPendingActions.add(new WeakReference<>(new PermissionAction()));
    
    
            int i = 0;
            WeakReference<PermissionAction> actionPermission = null;
    
            Iterator<WeakReference<PermissionAction>> iterator = mPendingActions.iterator();
    
            if(iterator.hasNext()){
                actionPermission = iterator.next();
            }
    
            while (true) {
                PermissionAction action = actionPermission.get();
    
                if (action != null) {
                    i++;
                    System.out.println("Object is alive for " + i + " loops - " + action);
                } else {
                    System.out.println("Object has been collected.");
                    break;
                }
    
            }
    
        }
    
    • WeakReference的一个特点是它何时被回收是不可确定的, 因为这是由GC运行的不确定性所确定的. 所以, 一般用weak reference引用的对象是有价值被cache, 而且很容易被重新被构建, 且很消耗内存的对象.

    虽然弱引用能让app避免了内存溢出的问题,但也带来了不确定性。

    弱引用可以用于Handler,一般的Handler写法可能会导致内存泄漏。因为非静态的内部类持有外部类的对象,而handler又会由于msg的处理而可能常驻在进程中,在activity或者service destroy后,不能及时被系统回收,导致内存泄漏。
    建议写法:

    private static class OuterHandler extends Handler {
        private final WeakReference<MainActivity> mActivity;
             
        public OuterHandler(MainActivity activity) {
          mActivity = new WeakReference<MainActivity>(activity);
        }
             
        @Override
        public void handleMessage(Message msg) {
          MainActivity activity = mActivity.get();
          if (activity != null) {
            // do something...
          }
        }
      }
    

    相关文章

      网友评论

          本文标题:WeakReference 弱引用与内存泄漏

          本文链接:https://www.haomeiwen.com/subject/oyrugttx.html