內存泄露實例分析 -- Android內存優化第四彈

cover

引言

前文內存分析工具集中介紹了一系列的內存分析工具及其基本使用, 諸如Memory Monitor, HPROF Viewer, MAT等等. 實際上了解了工具的使用, 我們就已經掌握了如何分析內存問題了.

為了能對工具的使用更加深入, 本篇將一個代碼片段為例, 從時序的角度講解下如何使用這些工具來分析一個內存泄露.

系列文:
1.GC那些事兒
2.Android的內存管理
3.內存分析工具
4.內存泄露實例分析

1, 例子

假設有一個單例的ListenerManager, 可以add / remove Listener, 有一個Activity, 實現了該listener, 且這個Activity中持有大對象BigObject, BigObject中包含一個大的字符串數組和一個Bitmap List.

代碼片段如下:

ListenerManager

public class ListenerManager {

    private static ListenerManager sInstance;
    private ListenerManager() {}

    private List<SampleListener> listeners = new ArrayList<>();

    public static ListenerManager getInstance() {
        if (sInstance == null) {
            sInstance = new ListenerManager();
        }

        return sInstance;
    }

    public void addListener(SampleListener listener) {
        listeners.add(listener);
    }

    public void removeListener(SampleListener listener) {
        listeners.remove(listener);
    }
}

MemoryLeakActivity

public class MemoryLeakActivity extends AppCompatActivity implements SampleListener {

    private BigObject mBigObject = new BigObject();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_memory_leak);

        ListenerManager.getInstance().addListener(this);
    }

    @Override
    public void doSomething() {

    }
}

具體代碼參看Github.

2, 使用Android Studio的自帶工具來分析

根據前文的工具介紹, Android Studio自帶了Memory Monitor, HPROF Viewer & Analyzer來分析內存使用及內存問題.

2.1 查看Memory使用, 并導出hprof文件

啟動我們要檢測的Activity(MemoryLeakActivity), 然后退出, 在monitor中查看內存變化:


2.2 在HPROF Viewer界面, 開始分析

第一步

點擊"Analyzer Tasks"視圖中的啟動按鈕, 啟動分析

第二步

查看"Analysis Result"中的分析結果, 點擊"Leaked Activityes"中的具體實例, 該實例的引用關系將會展示在"Reference Tree"視圖中.

第三步

根據"Reference Tree"視圖中的引用關系找到是誰讓這個leak的activity活著的, 也就是誰Dominate這個activity對象.

此例中, 比較簡單, 可以很清晰看到是ListenerManager的靜態單例sInstance最終支配了MemoryLeakActivity. sIntance連接到GC Roots, 故而導致MemoryLeakActivity GC Roots可達, 無法被回收.

關于Dominate, GC Roots, GC Roots可達, 活對象等概念, 請結合前兩篇的理論文1, 2觀看.

2.3 使用Heap Viewer查看內存消耗

上述步驟, 可以讓我們快速定位可能的內存泄露. 當然, 內存問題, 除了內存泄露, 還有內存消耗過大. 我們可以在Heap Viewer中查看分析內存的消耗點, 如下:

3, MAT讓我們看的更多

就單純的分析Android App的內存使用和內存泄露來說, 個人覺得Android Studio自帶的工具已經足夠好了, 而且再持續變得更好, 也更便于Android的開發人員去理解. 故而其實一開始在Android性能分析工具一文中, 我就沒有詳細去提MAT. 相對與Android Studio中的Memory Monitor, HPROF工具來說, MAT的使用顯得更加生澀, 難以理解.

關于MAT的幫助文檔, 個人翻譯了一份, 需要的同學戳這里.

當然, 如果我們想對內存的使用相關知識了解得更多, 還是有必要了解下MAT的...
下面我們以幾個角度來了解下MAT的基本使用:

再次:
Android Studio導出的hprof文件需要轉換下才可以在MAT中使用.

$ hprof-conv com.anly.samples_2016.10.31_15.07.hprof mat.hprof

3.1 Histogram視圖定位內存消耗

MAT中很多視圖的第一行, 都可以輸入正則, 來匹配我們關注的對象實例.

3.2 Dominate Tree視圖查看支配關系

3.3 使用OQL查詢相關對象

對于Android App開發來說, 大部分的內存問題都跟四大組件, 尤其是Activity相關, 故而我們會想查出所有Activity實例的內存占用情況, 可以使用OQL來查詢:


具體OQL語法看這里.

3.4 GC路徑定位問題

上面幾個視圖都可以讓我們很快速的找到內存的消耗點, 接下來我們要分析的就是為何這些個大對象沒有被回收.

根據第一彈:GC那些事兒所言, 對象沒有被回收是因為他有到GC Roots的可達路徑. 那么我們就來分析下這條路徑(Path to GC Roots), 看看是誰在這條路中"搭橋".

如下, 進入該對象的"path2gc"視圖:
![Slice 1](http://oat9lzupi.bkt.clouddn.com/Slice 1.jpg)

同樣, 與HPROF Analyzer異曲同工, 找出了是ListenerManager的靜態實例導致了MemoryLeakActivity無法回收.

4, LeakCanary讓內存泄露無處可藏

大道至簡, 程序員都應該"懶", 故而我們都希望有更方便快捷的方式讓我們發現內存泄露. 偉大的square發揮了這一優良傳統, LeakCanary面世.

4.1 加入LeakCanary

app的build.gradle中加入:

dependencies {
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
   testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
 }

Application中加入:

public class SampleApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        LeakCanary.install(this);
    }
}

4.2 操作要檢測的界面, 查看結果

當發生可疑內存泄露時, 會在桌面生成一個"Leaks"的圖標, 點擊進去可以看到內存泄露的疑點報告:


可以看到, 結果與前二者的分析結果"驚人"一致, 不一致就出事兒了, :)

足夠方便且直觀吧, 趕快用起來吧.
當然, 內存問題不僅僅是內存泄露, 還有內存占用過多等, 這時我們就需要借助前兩種工具了.

結語

綜上, 建議LeakCanary集成作為App的必選項, 大多數情況下我們可以用LeakCanary結合Android Studio自帶的工具分析內存問題.

如果有精力, 還是建議深入了解下MAT, 能讓我們更深入了解GC的機制, 相關概念, MAT還有很多更高端的功能值得我們探索, 例如Heap比較等.

其實, 內存問題的分析, 無外乎分析對象的內存占用(Retained Size), 找出Retained Size大的對象, 找到其直接支配(Immediate Dominator), 跟蹤其GC可達路徑(Path to GC Roots), 從而找到是誰讓這個大對象活著. 找到問題癥結, 對癥下藥.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,818評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,185評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,656評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,647評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,446評論 6 405
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,951評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,041評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,189評論 0 287
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,718評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,602評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,800評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,316評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,045評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,419評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,671評論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,420評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,755評論 2 371

推薦閱讀更多精彩內容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,604評論 25 707
  • 內存管理的目的就是讓我們在開發中怎么有效的避免我們的應用出現內存泄漏的問題。內存泄漏大家都不陌生了,簡單粗俗的講,...
    宇宙只有巴掌大閱讀 2,381評論 0 12
  • 四月的計劃完成的如何了?五月的計劃里,四月的計劃是否重復著? 四月的你,日子過得好么?五月的你,準備怎樣活? 上個...
    MsCactus閱讀 256評論 0 2
  • Q:小丸子張晗你好!聽說你是在職事業單位工作,同時業余時間兼職做微商,平時還要帶十個月大的寶寶,請問你為什么要參加...
    奔跑的丸子啊閱讀 498評論 9 52
  • 獨立歡騰舒駿馬,野鄉縱橫自乾坤。 平生不做安寧事,初老猶癡寨里春。 千里奮蹄戲千里,風云變換淡風云。 世間俗事逍遙...
    溪竹青閱讀 742評論 0 7