Android內(nèi)存分析工具 — Memory Profiler

目錄

前言

Android 存在內(nèi)存回收機制猴伶,當它確定應用不再使用某些對象時,垃圾回收器會將未使用的內(nèi)存釋放回堆中。 雖然 Android 查找未使用內(nèi)存的方式在不斷改進稳其,但對于所有 Android 版本扩氢,系統(tǒng)都必須在某個時間點短暫地暫停你寫的代碼耕驰。 大多數(shù)情況下,這些暫停難以察覺录豺。 但是朦肘,如果你的應用分配內(nèi)存的速度比系統(tǒng)回收內(nèi)存的速度快饭弓,那么當釋放足夠的內(nèi)存以滿足應用的分配需要時,應用就可能出現(xiàn)延遲媒抠。 這樣可能會導致應用跳幀弟断,并使系統(tǒng)明顯變慢

如果存在內(nèi)存泄漏,則即使應用在后臺運行也會保留該內(nèi)存领舰。 此行為會強制執(zhí)行不必要的垃圾回收事件夫嗓,因而拖慢系統(tǒng)的內(nèi)存性能。 最后冲秽,系統(tǒng)被迫終止你的應用進程以回收內(nèi)存舍咖。 然后,當用戶返回你的應用時锉桑,就必須完全重啟

為幫助防止這些問題排霉,我們可以使用Memory Profiler

  • 實時圖表展示應用內(nèi)存使用量
  • 識別內(nèi)存泄漏、抖動
  • 提供捕獲堆轉儲民轴、強制GC以及跟蹤內(nèi)存分配的能力

Memory Profiler 概覽

圖 1. Memory Profiler

如圖 1 所示攻柠,Memory Profiler 的默認視圖包括以下各項:

  1. 強制執(zhí)行垃圾回收

  2. 堆轉儲,把內(nèi)存信息通過文件的方式保存下來后裸,可以進行分析

  3. 記錄內(nèi)存分配情況瑰钮, 此按鈕僅在連接至運行 Android 7.1 或更低版本的設備時才會顯示

  4. 放大/縮小時間線

  5. 跳轉至實時內(nèi)存數(shù)據(jù)

  6. Event 時間線,顯示 Activity 狀態(tài)微驶、用戶輸入 Event 和屏幕旋轉 Event

  7. 內(nèi)存使用量時間線浪谴,其包含以下內(nèi)容:

    • 一個顯示每個內(nèi)存類別使用多少內(nèi)存的堆疊圖表,如左側的 y 軸以及頂部的彩色鍵所示

    • 虛線表示分配的對象數(shù)因苹,如右側的 y 軸所示

    • 用于表示每個垃圾回收 Event 的圖標

如何計算內(nèi)存占用

圖 2. Memory Profiler 頂部的內(nèi)存計數(shù)圖例

內(nèi)存計數(shù)中的類別如下所示:

  • Java:從 Java 或 Kotlin 代碼分配的對象內(nèi)存

  • Native:從 C 或 C++ 代碼分配的對象內(nèi)存

    即使你的應用中不使用 C++苟耻,你也可能會看到此處使用的一些原生內(nèi)存,因為 Android 框架使用原生內(nèi)存代表您處理各種任務扶檐,如處理圖像資源和其他圖形時凶杖,即使你編寫的代碼采用 Java 或 Kotlin 語言

  • Graphics:圖形緩沖區(qū)隊列向屏幕顯示像素(包括 GL 表面、GL 紋理等等)所使用的內(nèi)存 (請注意款筑,這是與 CPU 共享的內(nèi)存智蝠,不是 GPU 專用內(nèi)存)

  • Stack: 應用中的原生堆棧和 Java 堆棧使用的內(nèi)存。 這通常與您的應用運行多少線程有關

  • Code:應用用于處理代碼和資源(如 dex 字節(jié)碼奈梳、已優(yōu)化或已編譯的 dex 碼寻咒、.so 庫和字體)的內(nèi)存

  • Other:應用使用的系統(tǒng)不確定如何分類的內(nèi)存

  • Allocated:您的應用分配的 Java/Kotlin 對象數(shù)。 它沒有計入 C 或 C++ 中分配的對象

    當連接至運行 Android 7.1 及更低版本的設備時颈嚼,此分配僅在 Memory Profiler 連接至你運行的應用時才開始計數(shù)。 因此饭寺,你開始分析之前分配的任何對象都不會被計入阻课。 不過叫挟,Android 8.0 附帶一個設備內(nèi)置分析工具,該工具可記錄所有分配限煞,因此抹恳,在 Android 8.0 及更高版本上,此數(shù)字始終表示你的應用中待處理的 Java 對象總數(shù)

Java 數(shù)字可能與你在 Android Monitor 中看到的數(shù)字并非完全相同署驻,這是因為應用的 Java 堆是從 Zygote 啟動的奋献,而新數(shù)字則計入了為它分配的所有物理內(nèi)存頁面。 因此旺上,它可以準確反映你的應用實際使用了多少物理內(nèi)存

查看內(nèi)存分配

要檢查內(nèi)存分配記錄瓶蚂,可以按以下步驟操作:

  1. 瀏覽列表以查找堆計數(shù)異常大且可能存在泄漏的對象。 點擊 Class Name 列標題以按字母順序排序宣吱。 然后點擊一個類名稱窃这。 此時在右側將出現(xiàn) Instance View 窗格,顯示該類的每個實例征候,如圖 3 中所示
  2. Instance View 窗格中杭攻,點擊一個實例。 此時下方將出現(xiàn) Call Stack 標簽疤坝,顯示該實例被分配到何處以及哪個線程中
  3. Call Stack 標簽中兆解,點擊任意行以在編輯器中跳轉到該代碼
圖 3. 有關每個已分配對象的詳情顯示在右側的 **Instance View** 中

默認情況下,左側的分配列表按類名稱排列跑揉。 在列表頂部锅睛,你可以使用右側的下拉列表在以下排列方式之間進行切換:

  • Arrange by class:基于類名稱對所有分配進行分組
  • Arrange by package:基于軟件包名稱對所有分配進行分組
  • Arrange by callstack:將所有分配分組到其對應的調用堆棧

捕獲堆轉儲

堆轉儲顯示在您捕獲堆轉儲時您的應用中哪些對象正在使用內(nèi)存

要捕獲堆轉儲,在 Memory Profiler 工具欄中點擊 Dump Java heap

畔裕。 在轉儲堆期間衣撬,Java 內(nèi)存量可能會暫時增加。因為堆轉儲與您的應用發(fā)生在同一進程中扮饶,并需要一些內(nèi)存來收集數(shù)據(jù)

注:如果您需要更精確地了解轉儲的創(chuàng)建時間具练,可以通過調用 Debug.dumpHprofData() 在應用代碼的關鍵點創(chuàng)建堆轉儲

要檢查堆信息,請按以下步驟操作:

  1. 瀏覽列表以查找堆計數(shù)異常大且可能存在泄漏的對象甜无。 為幫助查找已知類扛点,點擊 Class Name 列標題以按字母順序排序。 然后點擊一個類名稱岂丘。 此時在右側將出現(xiàn) Instance View 窗格陵究,顯示該類的每個實例,如圖 5 中所示
  2. Instance View窗格中奥帘,點擊一個實例铜邮。此時下方將出現(xiàn)References,顯示該對象的每個引用
  3. References 標簽中,如果您發(fā)現(xiàn)某個引用可能在泄漏內(nèi)存松蒜,則右鍵點擊它并選擇 Go to Instance

在堆轉儲中扔茅,請注意由下列任意情況引起的內(nèi)存泄漏:

  • 長時間引用 ActivityContext秸苗、View召娜、Drawable 和其他對象,可能會保持對 ActivityContext 容器的引用
  • 可以保持 Activity 實例的非靜態(tài)內(nèi)部類惊楼,如 Runnable
  • 對象保持時間超出所需時間的緩存
圖 4. 捕獲堆轉儲需要的持續(xù)時間標示在時間線中

在類列表中玖瘸,你可以查看以下信息:

  • Heap Count:堆中的實例數(shù)
  • Shallow Size:此堆中所有實例的總大小(以字節(jié)為單位)
  • Retained Size:為此類的所有實例而保留的內(nèi)存總大刑戳(以字節(jié)為單位)

在類列表頂部雅倒,你可以使用左側下拉列表在以下堆轉儲之間進行切換:

  • Default heap:系統(tǒng)未指定堆時
  • App heap:應用在其中分配內(nèi)存的主堆
  • Image heap:系統(tǒng)啟動映像,包含啟動期間預加載的類攀芯。 此處的分配保證絕不會移動或消失
  • Zygote heap:寫時復制堆屯断,其中的應用進程是從 Android 系統(tǒng)中派生的

Instance View 中,每個實例都包含以下信息:

  • Depth:從任意 GC 根到所選實例的最短 hop 數(shù)
  • Shallow Size:此實例的大小
  • Retained Size:此實例支配的內(nèi)存大小

分析內(nèi)存的技巧

使用 Memory Profiler 時侣诺,你可以應用代碼施加壓力并嘗試強制內(nèi)存泄漏殖演。 在應用中引發(fā)內(nèi)存泄漏的一種方式是,先讓其運行一段時間年鸳,然后再檢查堆趴久。 泄漏在堆中可能逐漸匯聚到分配頂部。 不過搔确,泄漏越小彼棍,你越需要運行更長時間的應用才能看到泄漏

您還可以通過以下方式之一觸發(fā)內(nèi)存泄漏:

  • 將設備從縱向旋轉為橫向,然后在不同的 Activity 狀態(tài)下反復操作多次膳算。 旋轉設備經(jīng)常會導致應用泄漏 Activity座硕、ContextView 對象,因為系統(tǒng)會重新創(chuàng)建 Activity涕蜂,而如果您的應用在其他地方保持對這些對象之一的引用华匾,系統(tǒng)將無法對其進行垃圾回收
  • 處于不同的 Activity 狀態(tài)時,在您的應用與另一個應用之間切換(導航到主屏幕机隙,然后返回到您的應用)
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末蜘拉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子有鹿,更是在濱河造成了極大的恐慌旭旭,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件葱跋,死亡現(xiàn)場離奇詭異持寄,居然都是意外死亡源梭,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門际看,熙熙樓的掌柜王于貴愁眉苦臉地迎上來咸产,“玉大人,你說我怎么就攤上這事仲闽。” “怎么了僵朗?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵赖欣,是天一觀的道長。 經(jīng)常有香客問我验庙,道長顶吮,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任粪薛,我火速辦了婚禮悴了,結果婚禮上,老公的妹妹穿的比我還像新娘违寿。我一直安慰自己湃交,他們只是感情好,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布藤巢。 她就那樣靜靜地躺著搞莺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪掂咒。 梳的紋絲不亂的頭發(fā)上才沧,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音绍刮,去河邊找鬼温圆。 笑死,一個胖子當著我的面吹牛孩革,可吹牛的內(nèi)容都是我干的岁歉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼嫉戚,長吁一口氣:“原來是場噩夢啊……” “哼刨裆!你這毒婦竟也來了?” 一聲冷哼從身側響起彬檀,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤帆啃,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后窍帝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體努潘,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了疯坤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片报慕。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖压怠,靈堂內(nèi)的尸體忽然破棺而出眠冈,到底是詐尸還是另有隱情,我是刑警寧澤菌瘫,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布蜗顽,位于F島的核電站,受9級特大地震影響雨让,放射性物質發(fā)生泄漏雇盖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一栖忠、第九天 我趴在偏房一處隱蔽的房頂上張望崔挖。 院中可真熱鬧,春花似錦庵寞、人聲如沸狸相。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卷哩。三九已至,卻和暖如春属拾,著一層夾襖步出監(jiān)牢的瞬間将谊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工渐白, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留尊浓,地道東北人。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓纯衍,卻偏偏與公主長得像栋齿,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子襟诸,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345