LeakCanary2.0版本原理簡單查看

這幾天看了一下leakCanary2.0版本的源碼变勇,在這里做一下記錄禀苦。
2.0版本使用kotlin重寫的,使用起來也非常簡單遭铺,省去了在Application中的注冊丽柿,只需要在build.gradle文件中加入依賴

    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.0'

就可以了,代碼上什么都不用寫掂僵,完全做到了無感知操作航厚。

那么代碼上什么都不用寫,不用注冊它怎么來進行調(diào)用锰蓬,進行內(nèi)存監(jiān)測呢幔睬?
答案就在AppWatcherInstaller這個類上,它繼承了ContentProvider芹扭,屬于四大金剛麻顶,啊 不,四大組件之一舱卡。contentProvider的特點就是不用顯示調(diào)用初始化辅肾,在執(zhí)行完application的初始化后就會調(diào)用contentProvider的onCreate()方法。正是利用這一點轮锥,leakcanary把注冊寫在了這里面矫钓,有系統(tǒng)自動調(diào)用完成,對開發(fā)者完全無感知。
初次看leakCananry源碼新娜,我分了兩部分來看的:1赵辕、添加要觀察的對象 2、對對象進行觀察
第一部分概龄,添加觀察對象
在AppWatcherInstaller的onCreate中調(diào)用了InternalAppWatcher的install方法
1还惠、檢查是否是在主線程(不是的話拋出異常)
2、添加生命周期的回調(diào)私杜,在執(zhí)行onDestory的時候調(diào)用objectWatcher的watch方法蚕键,觀察這個activity的對象是否回收掉了

     ActivityDestroyWatcher.install(application, objectWatcher, configProvider)
//注冊fragment的watcher
    FragmentDestroyWatcher.install(application, objectWatcher, configProvider)

//ActivityDestroyWatcher里的部分代碼,再執(zhí)行onDestory的時候開始進行對象檢測

    private val lifecycleCallbacks =
       object : Application.ActivityLifecycleCallbacks by noOpDelegate() {
  override fun onActivityDestroyed(activity: Activity) {
    if (configProvider().watchActivities) {
      objectWatcher.watch(
          activity, "${activity::class.java.name} received Activity#onDestroy() callback"
      )
    }
  }
}

以上為注冊流程拇砰。
第二部分就是檢測對象的回收了
檢測對象的回收 起始類是ObjectWatcher,顧名思義對象觀察器咬崔。調(diào)用watch方法粱锐。ObjectWatcher.watch(watchedObject : Any,description : String)拟逮。watch方法里面做了如下操作:
在這個之前要先介紹一下,ObjectWatcher里面有兩個集合分別是:
1) private val watchedObjects = mutableMapOf<String, KeyedWeakReference>() 這是一個map集合达皿,用來存放要觀察對象的key和弱引用,代碼會為每個觀察的對象生成一個唯一的key和弱應用
2)private val queue = ReferenceQueue<Any>()watchedObjects 這個隊列和弱應用聯(lián)合使用叶洞,當弱引用中的對象被回收后,這個弱引用會被放到這個隊列中田篇。換句話說就是只要存在這個隊列中弱引用,就代表這個弱引用中所包含的對象被回收了箍铭。
下面開始watch方法里面的操作泊柬。
1、先移除watchedObjects 和queue 集合里面已經(jīng)回收對象的弱引用诈火。
2兽赁、通過uuid為當前觀察的對象生成一個唯一的key,并把對象用弱應用包起來,放到watchedObjects 這個集合中冷守,同時把queue 和弱應用關聯(lián)起來刀崖。
3、checkRetainedExecutor.execute {moveToRetained(key) }這里是個延遲任務拍摇,延遲五秒后再次執(zhí)行1操作亮钦,這個期間對象可能已經(jīng)被回收了,所以需要再次移除一次
4充活、執(zhí)行了3操作后蜂莉,就可以通過watchedObjects 集合找到?jīng)]有被回收的對象了。這時候就可以獲取到?jīng)]有被回收的對象的個數(shù)混卵,大于0映穗,進行一次gc操作(gc操作用的是Runtime.getRuntime() .gc(),源碼上注釋這個操作比system.gc()更可能觸發(fā)gc操作)幕随。

 var retainedReferenceCount = objectWatcher.retainedObjectCount
if (retainedReferenceCount > 0) {
  gcTrigger.runGc()
  retainedReferenceCount = objectWatcher.retainedObjectCount
}

5蚁滋、再次獲取未被回收的個數(shù),這一步會有幾個判斷條件
1)如果個數(shù)小于5,不做操作等待5秒再次進行檢查未回收的個數(shù),一直循環(huán)辕录,直到大于等于5個或者等于0個澄阳,為了防止頻發(fā)回收堆造成卡頓。
2)大于5個后踏拜,如果處于debug模式碎赢,會再等20秒,再次執(zhí)行4操作速梗。防止debug模式會減慢回收
3)距離上次堆棧分析是否大于等于1分鐘肮塞,如果沒有超過一分鐘,也需要再次延遲(1分鐘-當前距離上次的時間)再次循環(huán)4操作

6姻锁、如果上面的條件都符合了枕赵,就可以開始進行堆棧的分析了
1)、獲取到內(nèi)容文件 Debug.dumpHprofData(heapDumpFile.absolutePath)
2)位隶、objectWatcher.clearObjectsWatchedBefore(heapDumpUptimeMillis)該操作是去掉以前已經(jīng)分析過的對象拷窜,也就是去除掉之前的沒有回收掉的對象,不在本次分析范圍內(nèi)
3)涧黄、HeapAnalyzerService開啟IntentService服務進行分析 具體分析就不寫了篮昧,因為還沒看懂
4)、把結果插入數(shù)據(jù)庫(泄漏區(qū)分了應用本身的內(nèi)存泄漏和類庫的內(nèi)存泄漏)笋妥,并且發(fā)送通知

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末懊昨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子春宣,更是在濱河造成了極大的恐慌酵颁,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件月帝,死亡現(xiàn)場離奇詭異躏惋,居然都是意外死亡,警方通過查閱死者的電腦和手機嚷辅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門簿姨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人潦蝇,你說我怎么就攤上這事款熬。” “怎么了攘乒?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵贤牛,是天一觀的道長。 經(jīng)常有香客問我则酝,道長殉簸,這世上最難降的妖魔是什么闰集? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮般卑,結果婚禮上武鲁,老公的妹妹穿的比我還像新娘。我一直安慰自己蝠检,他們只是感情好沐鼠,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著叹谁,像睡著了一般饲梭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上焰檩,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天憔涉,我揣著相機與錄音,去河邊找鬼析苫。 笑死兜叨,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的衩侥。 我是一名探鬼主播国旷,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼顿乒!你這毒婦竟也來了议街?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤璧榄,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吧雹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體骨杂,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年雄卷,在試婚紗的時候發(fā)現(xiàn)自己被綠了搓蚪。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡丁鹉,死狀恐怖妒潭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情揣钦,我是刑警寧澤雳灾,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站冯凹,受9級特大地震影響谎亩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一匈庭、第九天 我趴在偏房一處隱蔽的房頂上張望夫凸。 院中可真熱鬧,春花似錦阱持、人聲如沸夭拌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽鸽扁。三九已至,卻和暖如春兵罢,著一層夾襖步出監(jiān)牢的瞬間献烦,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工卖词, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留巩那,地道東北人。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓此蜈,卻偏偏與公主長得像即横,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子裆赵,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容

  • 所有知識點已整理成app app下載地址 J2EE 部分: 1.Switch能否用string做參數(shù)东囚? 在 Jav...
    侯蛋蛋_閱讀 2,410評論 1 4
  • [TOC] 內(nèi)存管理 一、托管堆基礎 在面向?qū)ο笾姓绞冢總€類型代表一種可使用的資源页藻,要使用該資源,必須為代表資源的類...
    _秦同學_閱讀 3,781評論 0 3
  • 2.1 Activity 2.1.1 Activity的生命周期全面分析 典型情況下的生命周期:在用戶參與的情況下...
    AndroidMaster閱讀 3,023評論 0 8
  • 內(nèi)存管理的目的就是讓我們在開發(fā)中怎么有效的避免我們的應用出現(xiàn)內(nèi)存泄漏的問題植兰。內(nèi)存泄漏大家都不陌生了份帐,簡單粗俗的講,...
    宇宙只有巴掌大閱讀 2,360評論 0 12
  • 第二部分 自動內(nèi)存管理機制 第二章 java內(nèi)存異常與內(nèi)存溢出異常 運行數(shù)據(jù)區(qū)域 程序計數(shù)器:當前線程所執(zhí)行的字節(jié)...
    小明oh閱讀 1,130評論 0 2