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 常用工具詳解——內存優化 (三)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章