Android內(nèi)存優(yōu)化工具:Memory Profiler

一甥雕、簡介

Memory Profiler 是 Android Profiler 中的一個組件盏道,可幫助您識別導(dǎo)致應(yīng)用卡頓、凍結(jié)甚至崩潰的內(nèi)存泄漏和流失互艾。 它顯示一個應(yīng)用內(nèi)存使用量的實時圖表试和,讓您可以捕獲堆轉(zhuǎn)儲、強(qiáng)制執(zhí)行垃圾回收以及跟蹤內(nèi)存分配忘朝。

二灰署、為什么應(yīng)分析您的應(yīng)用內(nèi)存

Android 提供一個托管內(nèi)存環(huán)境—當(dāng)它確定您的應(yīng)用不再使用某些對象時,垃圾回收器會將未使用的內(nèi)存釋放回堆中。 雖然 Android 查找未使用內(nèi)存的方式在不斷改進(jìn)溉箕,但對于所有 Android 版本晦墙,系統(tǒng)都必須在某個時間點短暫地暫停您的代碼。 大多數(shù)情況下肴茄,這些暫停難以察覺晌畅。 不過,如果您的應(yīng)用分配內(nèi)存的速度比系統(tǒng)回收內(nèi)存的速度快寡痰,則當(dāng)收集器釋放足夠的內(nèi)存以滿足您的分配需要時抗楔,您的應(yīng)用可能會延遲。 此延遲可能會導(dǎo)致您的應(yīng)用跳幀拦坠,并使系統(tǒng)明顯變慢连躏。

盡管您的應(yīng)用不會表現(xiàn)出變慢,但如果存在內(nèi)存泄漏贞滨,則即使應(yīng)用在后臺運行也會保留該內(nèi)存入热。 此行為會強(qiáng)制執(zhí)行不必要的垃圾回收 Event,因而拖慢系統(tǒng)的內(nèi)存性能晓铆。 最后勺良,系統(tǒng)被迫終止您的應(yīng)用進(jìn)程以回收內(nèi)存。 然后骄噪,當(dāng)用戶返回您的應(yīng)用時尚困,它必須完全重啟。

為幫助防止這些問題链蕊,您應(yīng)使用 Memory Profiler 執(zhí)行以下操作:

  • 在時間線中查找可能會導(dǎo)致性能問題的不理想的內(nèi)存分配模式事甜。
  • 轉(zhuǎn)儲 Java 堆以查看在任何給定時間哪些對象耗盡了使用內(nèi)存。 長時間進(jìn)行多個堆轉(zhuǎn)儲可幫助識別內(nèi)存泄漏滔韵。
  • 記錄正常用戶交互和極端用戶交互期間的內(nèi)存分配以準(zhǔn)確識別您的代碼在何處短時間分配了過多對象讳侨,或分配了泄漏的對象。

三奏属、Memory Profiler 概覽

要打開 Memory Profiler跨跨,可以以下步驟操作:


打開 Memory Profiler.png

當(dāng)您首次打開 Memory Profiler 時,您將看到一條表示應(yīng)用內(nèi)存使用量的詳細(xì)時間線囱皿,并可訪問用于強(qiáng)制執(zhí)行垃圾回收勇婴、捕捉堆轉(zhuǎn)儲和記錄內(nèi)存分配的各種工具。


Memory Profiler.png

如圖 1 所示嘱腥,Memory Profiler 的默認(rèn)視圖包括以下各項:

  1. 用于強(qiáng)制執(zhí)行垃圾回收 Event 的按鈕耕渴。
  2. 用于捕獲堆轉(zhuǎn)儲的按鈕。
  3. 用于記錄內(nèi)存分配情況的按鈕齿兔。 此按鈕僅在連接至運行 Android 7.1 或更低版本的設(shè)備時才會顯示橱脸。
  4. 用于放大/縮小時間線的按鈕础米。
  5. 用于跳轉(zhuǎn)至實時內(nèi)存數(shù)據(jù)的按鈕。
  6. Event 時間線添诉,其顯示 Activity 狀態(tài)屁桑、用戶輸入 Event 和屏幕旋轉(zhuǎn) Event。
  7. 內(nèi)存使用量時間線栏赴,其包含以下內(nèi)容:
    • 一個顯示每個內(nèi)存類別使用多少內(nèi)存的堆疊圖表蘑斧,如左側(cè)的 y 軸以及頂部的彩色鍵所示。
    • 虛線表示分配的對象數(shù)须眷,如右側(cè)的 y 軸所示竖瘾。
    • 用于表示每個垃圾回收 Event 的圖標(biāo)。

如何計算內(nèi)存

您在 Memory Profiler 頂部看到的數(shù)字取決于您的應(yīng)用根據(jù) Android 系統(tǒng)機(jī)制所創(chuàng)建的所有私有內(nèi)存花颗。 此計數(shù)不包含與系統(tǒng)或其他應(yīng)用共享的內(nèi)存捕传。


內(nèi)存計數(shù).png

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

  • Java:從 Java 或 Kotlin 代碼分配的對象內(nèi)存。
  • Native:從 C 或 C++ 代碼分配的對象內(nèi)存扩劝。
    即使您的應(yīng)用中不使用 C++乐横,您也可能會看到此處使用的一些原生內(nèi)存,如處理圖像資源和其他圖形時今野,即使您編寫的代碼采用 Java 或 Kotlin 語言,Android 框架也會使用原生內(nèi)存處理各種任務(wù)罐农。
  • Graphics:圖形緩沖區(qū)隊列向屏幕顯示像素(包括 GL 表面条霜、GL 紋理等等)所使用的內(nèi)存。 (請注意涵亏,這是與 CPU 共享的內(nèi)存宰睡,不是 GPU 專用內(nèi)存。)
  • Stack: 您的應(yīng)用中的原生堆棧和 Java 堆棧使用的內(nèi)存气筋。 這通常與您的應(yīng)用運行多少線程有關(guān)拆内。
  • Code:您的應(yīng)用用于處理代碼和資源(如 dex 字節(jié)碼、已優(yōu)化或已編譯的 dex 碼宠默、.so 庫和字體)的內(nèi)存麸恍。
  • Other:您的應(yīng)用使用的系統(tǒng)不確定如何分類的內(nèi)存。
  • Allocated:您的應(yīng)用分配的 Java/Kotlin 對象數(shù)搀矫。 它沒有計入 C 或 C++ 中分配的對象抹沪。

四、查看內(nèi)存分配

內(nèi)存分配顯示內(nèi)存中每個對象是如何分配的瓤球。 具體而言融欧,Memory Profiler 可為您顯示有關(guān)對象分配的以下信息:

  • 分配哪些類型的對象以及它們使用多少空間。
  • 每個分配的堆疊追蹤卦羡,包括在哪個線程中噪馏。
  • 對象在何時被取消分配(僅當(dāng)使用運行 Android 8.0 或更高版本的設(shè)備時)麦到。

如果您的設(shè)備運行 Android 8.0 或更高版本,您可以隨時按照下述方法查看您的對象分配: 只需點擊并按住時間線欠肾,并拖動選擇您想要查看分配的區(qū)域(如下圖所示)瓶颠。 不需要開始記錄會話,因為 Android 8.0 及更高版本附帶設(shè)備內(nèi)置分析工具董济,可持續(xù)跟蹤您的應(yīng)用分配步清。


image.gif

要檢查分配記錄,請按以下步驟操作:

  • 瀏覽列表以查找堆計數(shù)異常大且可能存在泄漏的對象虏肾。 為幫助查找已知類廓啊,點擊 Class Name 列標(biāo)題以按字母順序排序。 然后點擊一個類名稱封豪。 此時在右側(cè)將出現(xiàn) Instance View 窗格谴轮,顯示該類的每個實例,如圖中所示吹埠。
  • 在 Instance View 窗格中第步,點擊一個實例。 此時下方將出現(xiàn) Call Stack 標(biāo)簽缘琅,顯示該實例被分配到何處以及哪個線程中粘都。
  • 在 Call Stack 標(biāo)簽中,點擊任意行以在編輯器中跳轉(zhuǎn)到該代碼刷袍。


    image.png

    默認(rèn)情況下翩隧,左側(cè)的分配列表按類名稱排列。 在列表頂部呻纹,您可以使用右側(cè)的下拉列表在以下排列方式之間進(jìn)行切換:

  • Arrange by class:基于類名稱對所有分配進(jìn)行分組堆生。
  • Arrange by package:基于軟件包名稱對所有分配進(jìn)行分組。
  • Arrange by callstack:將所有分配分組到其對應(yīng)的調(diào)用堆棧雷酪。

五淑仆、捕獲堆轉(zhuǎn)儲

堆轉(zhuǎn)儲顯示在您捕獲堆轉(zhuǎn)儲時您的應(yīng)用中哪些對象正在使用內(nèi)存。 特別是在長時間的用戶會話后哥力,堆轉(zhuǎn)儲會顯示您認(rèn)為不應(yīng)再位于內(nèi)存中卻仍在內(nèi)存中的對象蔗怠,從而幫助識別內(nèi)存泄漏。 在捕獲堆轉(zhuǎn)儲后吩跋,您可以查看以下信息:

  • 您的應(yīng)用已分配哪些類型的對象蟀淮,以及每個類型分配多少。
  • 每個對象正在使用多少內(nèi)存钞澳。
  • 在代碼中的何處仍在引用每個對象怠惶。
  • 對象所分配到的調(diào)用堆棧。 (目前轧粟,如果您在記錄分配時捕獲堆轉(zhuǎn)儲策治,則只有在 Android 7.1 及更低版本中脓魏,堆轉(zhuǎn)儲才能使用調(diào)用堆棧。)


    查看堆轉(zhuǎn)儲.png

要捕獲堆轉(zhuǎn)儲通惫,在 Memory Profiler 工具欄中點擊 Dump Java heap 茂翔。 在轉(zhuǎn)儲堆期間,Java 內(nèi)存量可能會暫時增加履腋。 這很正常珊燎,因為堆轉(zhuǎn)儲與您的應(yīng)用發(fā)生在同一進(jìn)程中,并需要一些內(nèi)存來收集數(shù)據(jù)遵湖。

堆轉(zhuǎn)儲顯示在內(nèi)存時間線下悔政,顯示堆中的所有類類型,如上圖所示延旧。

如果您需要更精確地了解轉(zhuǎn)儲的創(chuàng)建時間谋国,可以通過調(diào)用 dumpHprofData() 在應(yīng)用代碼的關(guān)鍵點創(chuàng)建堆轉(zhuǎn)儲。

要檢查您的堆迁沫,請按以下步驟操作:

  1. 瀏覽列表以查找堆計數(shù)異常大且可能存在泄漏的對象芦瘾。 為幫助查找已知類,點擊 Class Name 列標(biāo)題以按字母順序排序集畅。 然后點擊一個類名稱近弟。 此時在右側(cè)將出現(xiàn) Instance View 窗格,顯示該類的每個實例挺智,如圖 5 中所示祷愉。
  2. Instance View 窗格中,點擊一個實例逃贝。此時下方將出現(xiàn) References,顯示該對象的每個引用迫摔。
    或者沐扳,點擊實例名稱旁的箭頭以查看其所有字段,然后點擊一個字段名稱查看其所有引用句占。 如果您要查看某個字段的實例詳情沪摄,右鍵點擊該字段并選擇 Go to Instance
  3. References 標(biāo)簽中纱烘,如果您發(fā)現(xiàn)某個引用可能在泄漏內(nèi)存杨拐,則右鍵點擊它并選擇 Go to Instance。 這將從堆轉(zhuǎn)儲中選擇對應(yīng)的實例擂啥,顯示您自己的實例數(shù)據(jù)哄陶。

默認(rèn)情況下,堆轉(zhuǎn)儲不會向您顯示每個已分配對象的堆疊追蹤哺壶。 要獲取堆疊追蹤屋吨,在點擊 Dump Java heap 之前蜒谤,您必須先開始記錄內(nèi)存分配。 然后至扰,您可以在 Instance View 中選擇一個實例鳍徽,并查看 Call Stack 標(biāo)簽以及 References 標(biāo)簽,如圖 5 所示敢课。不過阶祭,在您開始記錄分配之前,可能已分配一些對象直秆,因此濒募,調(diào)用堆棧不能用于這些對象。 包含調(diào)用堆棧的實例在圖標(biāo)

堆棧實例在圖標(biāo)

上用一個“堆椙欣澹”標(biāo)志表示萨咳。 (遺憾的是,由于堆疊追蹤需要您執(zhí)行分配記錄疫稿,因此培他,您目前無法在 Android 8.0 上查看堆轉(zhuǎn)儲的堆疊追蹤。)

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

  • 長時間引用 Activity舀凛、ContextView途蒋、Drawable 和其他對象猛遍,可能會保持對 ActivityContext 容器的引用。
  • 可以保持 Activity 實例的非靜態(tài)內(nèi)部類号坡,如 Runnable懊烤。
  • 對象保持時間超出所需時間的緩存。
捕獲堆轉(zhuǎn)儲需要的持續(xù)時間標(biāo)示在時間線中.png

在類列表中宽堆,您可以查看以下信息:

  • Heap Count:堆中的實例數(shù)腌紧。
  • Shallow Size:此堆中所有實例的總大小(以字節(jié)為單位)畜隶。
  • Retained Size:為此類的所有實例而保留的內(nèi)存總大斜诶摺(以字節(jié)為單位)。

在類列表頂部籽慢,您可以使用左側(cè)下拉列表在以下堆轉(zhuǎn)儲之間進(jìn)行切換:

  • Default heap:系統(tǒng)未指定堆時浸遗。
  • App heap:您的應(yīng)用在其中分配內(nèi)存的主堆。
  • Image heap:系統(tǒng)啟動映像箱亿,包含啟動期間預(yù)加載的類跛锌。 此處的分配保證絕不會移動或消失。
  • Zygote heap:寫時復(fù)制堆届惋,其中的應(yīng)用進(jìn)程是從 Android 系統(tǒng)中派生的察净。

默認(rèn)情況下驾茴,此堆中的對象列表按類名稱排列。 您可以使用其他下拉列表在以下排列方式之間進(jìn)行切換:

  • Arrange by class:基于類名稱對所有分配進(jìn)行分組氢卡。
  • Arrange by package:基于軟件包名稱對所有分配進(jìn)行分組锈至。
  • Arrange by callstack:將所有分配分組到其對應(yīng)的調(diào)用堆棧。 此選項僅在記錄分配期間捕獲堆轉(zhuǎn)儲時才有效译秦。 即使如此峡捡,堆中的對象也很可能是在您開始記錄之前分配的,因此這些分配會首先顯示筑悴,且只按類名稱列出们拙。

默認(rèn)情況下,此列表按 Retained Size 列排序阁吝。 您可以點擊任意列標(biāo)題以更改列表的排序方式砚婆。
在 Instance View 中,每個實例都包含以下信息:

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

將堆轉(zhuǎn)儲另存為 HPROF

要使用其他 HPROF 分析器(如MAT),您需要將 HPROF 文件從 Android 格式轉(zhuǎn)換為 Java SE HPROF 格式甲馋。 您可以使用 android_sdk/platform-tools/ 目錄中提供的 hprof-conv 工具執(zhí)行此操作埂奈。 運行包括以下兩個參數(shù)的 hprof-conv 命令:原始 HPROF 文件和轉(zhuǎn)換后 HPROF 文件的寫入位置。 例如:

hprof-conv heap-original.hprof heap-converted.hprof

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末定躏,一起剝皮案震驚了整個濱河市账磺,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌痊远,老刑警劉巖垮抗,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異碧聪,居然都是意外死亡冒版,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進(jìn)店門矾削,熙熙樓的掌柜王于貴愁眉苦臉地迎上來壤玫,“玉大人豁护,你說我怎么就攤上這事哼凯。” “怎么了楚里?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵断部,是天一觀的道長。 經(jīng)常有香客問我班缎,道長蝴光,這世上最難降的妖魔是什么她渴? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蔑祟,結(jié)果婚禮上趁耗,老公的妹妹穿的比我還像新娘。我一直安慰自己疆虚,他們只是感情好苛败,可當(dāng)我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著径簿,像睡著了一般罢屈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上篇亭,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天缠捌,我揣著相機(jī)與錄音,去河邊找鬼译蒂。 笑死曼月,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蹂随。 我是一名探鬼主播十嘿,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼岳锁!你這毒婦竟也來了绩衷?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤激率,失蹤者是張志新(化名)和其女友劉穎咳燕,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乒躺,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡招盲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了嘉冒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片曹货。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖讳推,靈堂內(nèi)的尸體忽然破棺而出顶籽,到底是詐尸還是另有隱情,我是刑警寧澤银觅,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布礼饱,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏镊绪。R本人自食惡果不足惜匀伏,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蝴韭。 院中可真熱鬧够颠,春花似錦、人聲如沸榄鉴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽牢硅。三九已至蹬耘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間减余,已是汗流浹背综苔。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留位岔,地道東北人如筛。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像抒抬,于是被迫代替她去往敵國和親杨刨。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,033評論 2 355

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