LeakCanary-內(nèi)存泄漏檢測神器簡介

一沈贝、什么是內(nèi)存泄漏?
在Android的開發(fā)中踩晶,經(jīng)常聽到“內(nèi)存泄漏”這個詞执泰。“內(nèi)存泄漏”就是一個對象已經(jīng)不需要再使用了渡蜻,但是因為其它的對象持有該對象的引用术吝,導(dǎo)致它的內(nèi)存不能被回收。那么在android開發(fā)過程中茸苇,有哪些比較常見的場景呢排苍?
其實主要就是activity或者fragment內(nèi)存泄漏了。
那么学密,泄漏的原因一般有哪些呢淘衙?
1、數(shù)據(jù)庫游標(biāo)忘記關(guān)閉了腻暮。
2幔翰、bitmap忘記回收
3漩氨、不當(dāng)?shù)氖褂胔andler
4、timer等不當(dāng)?shù)氖褂谩?br> 5遗增、地圖等
總之,歸納起來一句話來講:

目前開發(fā)者遇到的內(nèi)存泄漏普遍就是以上幾種了款青,這里列舉的僅僅是我遇到的比較多的場景做修,也不排除還有其他場景。

二抡草、那么遇到內(nèi)存泄漏一般是怎么追蹤并解決問題的呢饰及?
通常,開發(fā)者會利用android studio自帶的工具進(jìn)行分析:

1康震、讓自己的app先跑上一段時間燎含,在懷疑會產(chǎn)生內(nèi)存泄漏的幾個地方來回的多切換幾次。
然后腿短,打開著界面,在點擊這里。


先GC

對材蹬,通常先GC一下赡鲜,因為,內(nèi)存泄漏并不會因為GC而消除钝诚,GC只是將一些不必要的干擾因素排除掉而已颖御。
2、然后點GC右邊的那個按鈕凝颇,dump一下內(nèi)存潘拱,來進(jìn)行分析,dump之后拧略,自動出現(xiàn)這個界面


dum的內(nèi)存

為了方便查看芦岂,我們通常會根據(jù)包名Arrage by package分類查看,其實我們只關(guān)心自己應(yīng)用包名先的activity辑鲤,fragment之類的一些盔腔。
3、這里月褥,右邊會列舉出實例的個數(shù)弛随,通常出現(xiàn)幾個實例的activity其實就是你該嚴(yán)重懷疑的對象了,那么
找引用樹

根據(jù)這里的引用樹宁赤,最終層層剝根舀透,你就可以輕易發(fā)現(xiàn)最終是誰引用到了這個activity,而導(dǎo)致他泄漏了决左。
三愕够,恩走贪,回顧一下,這個過程惑芭,真是太麻煩了坠狡,那么,有沒有一個神器可以不用這么麻煩遂跟,就幫我們發(fā)現(xiàn)內(nèi)存泄漏逃沿,以及定位出原因呢?

答案顯然是有的幻锁,他就是 LeakCanary

LeakCanary

1凯亮、leak canary的原理:

實際上就是有一個線程專門去分析內(nèi)存圖譜,然后哄尔,有一些列的lifecircler之類的鉤子監(jiān)聽activity 的destory方法假消,如果一旦發(fā)現(xiàn)某個activity執(zhí)行的 destroy發(fā)放,但是岭接,他的實例還一直存在于內(nèi)存中富拗,那就判定這個activity泄漏了。
一下就是HeapAnalyzer的一段代碼片段:

 /**
   * Searches the heap dump for a {@link KeyedWeakReference} instance with the corresponding key,
   * and then computes the shortest strong reference path from that instance to the GC roots.
   */
  public AnalysisResult checkForLeak(File heapDumpFile, String referenceKey) {
    long analysisStartNanoTime = System.nanoTime();

    if (!heapDumpFile.exists()) {
      Exception exception = new IllegalArgumentException("File does not exist: " + heapDumpFile);
      return failure(exception, since(analysisStartNanoTime));
    }

    try {
      HprofBuffer buffer = new MemoryMappedFileBuffer(heapDumpFile);
      HprofParser parser = new HprofParser(buffer);
      Snapshot snapshot = parser.parse();
      deduplicateGcRoots(snapshot);

      Instance leakingRef = findLeakingReference(referenceKey, snapshot);

      // False alarm, weak reference was cleared in between key check and heap dump.
      if (leakingRef == null) {
        return noLeak(since(analysisStartNanoTime));
      }

      return findLeakTrace(analysisStartNanoTime, snapshot, leakingRef);
    } catch (Throwable e) {
      return failure(e, since(analysisStartNanoTime));
    }
  }

private AnalysisResult findLeakTrace(long analysisStartNanoTime, Snapshot snapshot,
      Instance leakingRef) {

    ShortestPathFinder pathFinder = new ShortestPathFinder(excludedRefs);
    ShortestPathFinder.Result result = pathFinder.findPath(snapshot, leakingRef);

    // False alarm, no strong reference path to GC Roots.
    if (result.leakingNode == null) {
      return noLeak(since(analysisStartNanoTime));
    }

    LeakTrace leakTrace = buildLeakTrace(result.leakingNode);

    String className = leakingRef.getClassObj().getClassName();

    // Side effect: computes retained size.
    snapshot.computeDominators();

    Instance leakingInstance = result.leakingNode.instance;

    long retainedSize = leakingInstance.getTotalRetainedSize();

    // TODO: check O sources and see what happened to android.graphics.Bitmap.mBuffer
    if (SDK_INT <= N_MR1) {
      retainedSize += computeIgnoredBitmapRetainedSize(snapshot, leakingInstance);
    }

    return leakDetected(result.excludingKnownLeaks, className, leakTrace, retainedSize,
        since(analysisStartNanoTime));
  }

其中亿傅,這段代碼清晰表明:

      Instance leakingRef = findLeakingReference(referenceKey, snapshot);

      // False alarm, weak reference was cleared in between key check and heap dump.
      if (leakingRef == null) {
        return noLeak(since(analysisStartNanoTime));
      }

      return findLeakTrace(analysisStartNanoTime, snapshot, leakingRef);  

如果一個該銷毀的context還被持有媒峡,那么就是泄漏了。

2葵擎、leak canary 使用:
如果你使用android studio開發(fā)谅阿,那么相當(dāng)簡單

在build.gralde中添加
dependencies {
  debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.4'
  releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'
}

然后:在你的Application中添加一下代碼即可。
public class ExampleApplication extends Application {

  @Override public void onCreate() {
    super.onCreate();
    if (LeakCanary.isInAnalyzerProcess(this)) {
      // This process is dedicated to LeakCanary for heap analysis.
      // You should not init your app in this process.
      return;
    }
    LeakCanary.install(this);
    // Normal app init code...
  }
}

其中

releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.4'

是一個空操作集合酬滤,表示签餐,在生產(chǎn)環(huán)境下,不會進(jìn)行內(nèi)心泄漏檢測盯串,只是在開發(fā)調(diào)試環(huán)境起作用氯檐,為什么要這么做呢?很顯然体捏,一個是為了app流暢冠摄,內(nèi)存泄漏分析是需要消耗性能的,第二個几缭,用戶其實對你的app內(nèi)存泄漏并不關(guān)心河泳,一般用戶也不明白這是個什么鬼,你突然彈出一個提醒說某某activity泄漏了年栓,用戶也是一臉懵逼拆挥。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市某抓,隨后出現(xiàn)的幾起案子纸兔,更是在濱河造成了極大的恐慌惰瓜,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件汉矿,死亡現(xiàn)場離奇詭異崎坊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)负甸,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門流强,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人呻待,你說我怎么就攤上這事《痈” “怎么了蚕捉?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長柴淘。 經(jīng)常有香客問我迫淹,道長,這世上最難降的妖魔是什么为严? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任敛熬,我火速辦了婚禮,結(jié)果婚禮上第股,老公的妹妹穿的比我還像新娘应民。我一直安慰自己,他們只是感情好夕吻,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布诲锹。 她就那樣靜靜地躺著,像睡著了一般涉馅。 火紅的嫁衣襯著肌膚如雪归园。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天稚矿,我揣著相機(jī)與錄音庸诱,去河邊找鬼。 笑死晤揣,一個胖子當(dāng)著我的面吹牛桥爽,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播碉渡,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼聚谁,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了滞诺?” 一聲冷哼從身側(cè)響起形导,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤环疼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后朵耕,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體炫隶,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年阎曹,在試婚紗的時候發(fā)現(xiàn)自己被綠了伪阶。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡处嫌,死狀恐怖栅贴,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情熏迹,我是刑警寧澤檐薯,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站注暗,受9級特大地震影響坛缕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜捆昏,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一赚楚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧骗卜,春花似錦宠页、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至焚刺,卻和暖如春敛摘,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背乳愉。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工兄淫, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人蔓姚。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓捕虽,卻偏偏與公主長得像,于是被迫代替她去往敵國和親坡脐。 傳聞我的和親對象是個殘疾皇子泄私,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355

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