MVP内存泄漏全解(笔记)

Posted 巨头之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MVP内存泄漏全解(笔记)相关的知识,希望对你有一定的参考价值。

前言

基于MVP 模式的理解进行内存泄漏的测试

1.对MvpSample2工程的测试(测试记录)
  • 第一次: 清理弱引用和解除rx的订阅,rx里面没开线程跑,虽然栈中存在presenter$tologin$1,但是引用为0.,所以内存不泄漏

  • 第二次:清理弱引用和解除rx的订阅,rx里面开了新的线程跑,presenter对象被线程所持有,activity引用不存在,presenter的内存泄漏了

  • 第三次:清理弱引用和解除rx的订阅,rx里面上游开了循环(在上游的线程跑),虽然内存中存在presenter$tologin$1,内存不泄漏,跟第一次一样

  • 第四次:没有清理弱引用和解除rx的订阅,rx里面没开线程跑,虽然内存中存在presenter$tologin$1,但是引用为0.,所以内存不泄漏

  • 第五次:没有清理弱引用和解除rx的订阅,rx里面上游开了循环(在上游的线程跑),presenter的引用被rx上游线程持有,释放不了,内存泄漏了,而View已经不存在内存,是因为View在P层中加了弱引用

  • 第六次:V在P层中是强引用持有,没有解除rx的订阅,rx里面上游开了循环(在上游的线程跑), presenter和View都回收不了,因为线程持有P的引用,还在运行中

  • 第七次:V在P层中是强引用持有,解除rx的订阅,rx里面上游开了循环(在上游的线程跑), 虽然内存中存在presenter$tologin$1,但是引用为0.,所以内存不泄漏

2.截图说明
  • 截图1 :从GC Roots节点到该对象(LoginPresenter)的最短引用路径, 排除弱引用/软引用

  • 截图2 : 从截图1过渡到截图2,可以看到LoginPresenter是被线程持有引用

  • 截图3 : 从profiler可以看到LoginPresenter是被线程持有引用

  • 截图4 : 从profiler可以看到LoginModel是被LoginPresenter持有引用,LoginPresenter是被线程持有引用

  • 截图5 : objects是存在实例的个数,Shallow Heap浅堆是Java对象占用的内存,Retained Heap深堆是java对象及对象引用的类占用的内存、jvm gc回收时释放的内存

  • 截图6:V被P强引用持有引用,P被运行的任务(可能内部类)持有引用,导致V层和P层都内存泄漏

3.总结:
  • p层的耗时任务在页面销毁时是否执行很关键:假设当页面销毁时,presenter层内的任务执行完,由于presenter没有再被内部类等持有引用,所以presenter是会被回收的,那view层也不被presenter持有引用,所以即使没在View销毁时清空软引用和置View为null,View同样会被销毁,不存在内存泄漏问题

  • V层是否被presenter弱引用持有决定V层是否会内存泄漏:假设当页面销毁时,presenter层内的任务在执行, 由于V是被presenter弱引用持有,所以V是会被GC回收的,而Presenter由于任务还在执行,所以回收不了

  • 页面销毁时结束耗时任务可解决presenter和View的内存泄漏, 假设当页面销毁时,即使presenter对View是强引用持有,只要此时任务执行完或者解绑Rx的订阅,presenter和View都是可以被回收的,所以不存在内存泄漏

  • Rx上游创建异步耗时线程跑,即使取消订阅,还是会内存泄漏,可能Rx不知道开了一个子线程在跑,而子线程持有presenter的引用

  • 线程的调度放心交给Rx来处理:Rx上游创建异步耗时线程跑,即使取消订阅,还是会内存泄漏,可能Rx不知道开了一个子线程在跑,而子线程持有presenter的引用 (这里参考链接 在Rx的上游执行异步耗时任务的测试)

  • 所以发生泄漏主要在: presenter的引用被rx开辟的线程所持有(或者Model的引用被持有), 从而导致V的引用被持有

    • 线程运行中,而View界面已经关闭,由于presenter不能被回收(被内部类持有引用),所以导致presenter内存泄漏

      • 而如果View是被Presenter强引用持有的话,那View也不能被回收

      • 而如果View是被presenter弱引用持有的话,那么View是可以被GC回收的

    • View的界面销毁, 此时线程运行结束或解除rx的订阅,由于presenter已不再被持有引用,故可GC回收, 而不管View是被Presenter强引用还是弱引用,View都会被GC回收

  • MVP的内存泄漏可以通过解除Rx的订阅(RxLifecycle2框架或AutoDispose框架)来解决,前提是耗时任务都在Rx里去操作, 使得Model、View、Presenter不被持有引用,从而可回收

4.参考

使用AndroidStudio提供的Android Profiler工具和mat进行内存泄漏析

在Rx的上游执行异步耗时任务的测试

MAT 常用工具详解——内存优化 (三)

以上是关于MVP内存泄漏全解(笔记)的主要内容,如果未能解决你的问题,请参考以下文章

Android开发:浅谈MVP模式应用与内存泄漏

Android内存泄漏查找和解决

动态内存管理

动态内存分配

动态内存管理

Android内存泄漏分析实战