Memory Profiler 是 Android Profiler 中的一個組件何址,可幫助你分析應(yīng)用卡頓吨灭、崩潰系馆、內(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)確識別您的代碼在何處短時間分配了過多對象,或分配了泄漏的對象骡湖。
如需了解可減少應(yīng)用內(nèi)存使用的編程做法贱纠,請閱讀管理您的應(yīng)用內(nèi)存。
Memory Profiler 概覽
當(dāng)您首次打開 Memory Profiler 時响蕴,您將看到一條表示應(yīng)用內(nèi)存使用量的詳細(xì)時間線谆焊,并可訪問用于強(qiáng)制執(zhí)行垃圾回收、捕捉堆轉(zhuǎn)儲和記錄內(nèi)存分配的各種工具浦夷。
如圖 1 所示辖试,Memory Profiler 的默認(rèn)視圖包括以下各項:
- 用于強(qiáng)制執(zhí)行垃圾回收 Event 的按鈕。
- 用于捕獲堆轉(zhuǎn)儲的按鈕
- 用于記錄內(nèi)存分配情況的按鈕劈狐。 此按鈕僅在連接至運行 Android 7.1 或更低版本的設(shè)備時才會顯示罐孝。
- 用于放大/縮小時間線的按鈕。
- 用于跳轉(zhuǎn)至實時內(nèi)存數(shù)據(jù)的按鈕肥缔。
- Event 時間線莲兢,其顯示 Activity 狀態(tài)、用戶輸入 Event 和屏幕旋轉(zhuǎn) Event续膳。
- 內(nèi)存使用量時間線改艇,其包含以下內(nèi)容:
- 一個顯示每個內(nèi)存類別使用多少內(nèi)存的堆疊圖表,如左側(cè)的 y 軸以及頂部的彩色鍵所示坟岔。
- 虛線表示分配的對象數(shù)谒兄,如右側(cè)的 y 軸所示。
- 用于表示每個垃圾回收 Event 的圖標(biāo)炮车。
不過舵变,如果您使用的是運行 Android 7.1 或更低版本的設(shè)備,則默認(rèn)情況下瘦穆,并不是所有分析數(shù)據(jù)均可見纪隙。 如果您看到一條消息,其顯示“Advanced profiling is unavailable for the selected process”扛或,則需要啟用高級分析以查看下列內(nèi)容:
- Event 時間線
- 分配的對象數(shù)
- 垃圾回收 Event
在 Android 8.0 及更高版本上绵咱,始終為可調(diào)試應(yīng)用啟用高級分析。
如何計算內(nèi)存
您在 Memory Profiler(圖 2)頂部看到的數(shù)字取決于您的應(yīng)用根據(jù) Android 系統(tǒng)機(jī)制所提交的所有私有內(nèi)存頁面數(shù)熙兔。 此計數(shù)不包含與系統(tǒng)或其他應(yīng)用共享的頁面悲伶。
內(nèi)存計數(shù)中的類別如下所示:
- Java:從 Java 或 Kotlin 代碼分配的對象內(nèi)存艾恼。
-
Native:從 C 或 C++ 代碼分配的對象內(nèi)存。
即使您的應(yīng)用中不使用 C++麸锉,您也可能會看到此處使用的一些原生內(nèi)存钠绍,因為 Android 框架使用原生內(nèi)存代表您處理各種任務(wù),如處理圖像資源和其他圖形時花沉,即使您編寫的代碼采用 Java 或 Kotlin 語言柳爽。 - 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++ 中分配的對象展辞。
當(dāng)連接至運行 Android 7.1 及更低版本的設(shè)備時奥邮,此分配僅在 Memory Profiler 連接至您運行的應(yīng)用時才開始計數(shù)。 因此罗珍,您開始分析之前分配的任何對象都不會被計入洽腺。 不過,Android 8.0 附帶一個設(shè)備內(nèi)置分析工具覆旱,該工具可記錄所有分配蘸朋,因此,在 Android 8.0 及更高版本上扣唱,此數(shù)字始終表示您的應(yīng)用中待處理的 Java 對象總數(shù)藕坯。
與以前的 Android Monitor 工具中的內(nèi)存計數(shù)相比,新的 Memory Profiler 以不同的方式記錄您的內(nèi)存噪沙,因此炼彪,您的內(nèi)存使用量現(xiàn)在看上去可能會更高些。 Memory Profiler 監(jiān)控的類別更多正歼,這會增加總的內(nèi)存使用量辐马,但如果您僅關(guān)心 Java 堆內(nèi)存,則“Java”項的數(shù)字應(yīng)與以前工具中的數(shù)值相似局义。
然而喜爷,Java 數(shù)字可能與您在 Android Monitor 中看到的數(shù)字并非完全相同冗疮,這是因為應(yīng)用的 Java 堆是從 Zygote 啟動的,而新數(shù)字則計入了為它分配的所有物理內(nèi)存頁面檩帐。 因此术幔,它可以準(zhǔn)確反映您的應(yīng)用實際使用了多少物理內(nèi)存。
注:目前湃密,Memory Profiler 還會顯示應(yīng)用中的一些誤報的原生內(nèi)存使用量特愿,而這些內(nèi)存實際上是分析工具使用的。 對于大約 100000 個對象勾缭,最多會使報告的內(nèi)存使用量增加 10MB揍障。 在這些工具的未來版本中,這些數(shù)字將從您的數(shù)據(jù)中過濾掉俩由。
查看內(nèi)存分配
內(nèi)存分配顯示內(nèi)存中每個對象是如何分配的毒嫡。 具體而言,Memory Profiler 可為您顯示有關(guān)對象分配的以下信息:
- 分配哪些類型的對象以及它們使用多少空間幻梯。
- 每個分配的堆疊追蹤兜畸,包括在哪個線程中。
- 對象在何時被取消分配(僅當(dāng)使用運行 Android 8.0 或更高版本的設(shè)備時)碘梢。
如果您的設(shè)備運行 Android 8.0 或更高版本咬摇,您可以隨時按照下述方法查看您的對象分配: 只需點擊并按住時間線,并拖動選擇您想要查看分配的區(qū)域(如圖 3中所示)煞躬。 不需要開始記錄會話肛鹏,因為 Android 8.0 及更高版本附帶設(shè)備內(nèi)置分析工具,可持續(xù)跟蹤您的應(yīng)用分配恩沛。
使用 Memory Profiler 查看 Java 堆和內(nèi)存分配
Memory Profiler 是 Android Profiler 中的一個組件,可幫助您識別導(dǎo)致應(yīng)用卡頓雷客、凍結(jié)甚至崩潰的內(nèi)存泄漏和流失芒珠。 它顯示一個應(yīng)用內(nèi)存使用量的實時圖表,讓您可以捕獲堆轉(zhuǎn)儲搅裙、強(qiáng)制執(zhí)行垃圾回收以及跟蹤內(nèi)存分配皱卓。
要打開 Memory Profiler,請按以下步驟操作:
-
點擊 View > Tool Windows > Android Profiler(也可以點擊工具欄中的 Android Profiler [圖片上傳中...(image-2c570a-1533109180178-0)]
)部逮。
從 Android Profiler 工具欄中選擇您想要分析的設(shè)備和應(yīng)用進(jìn)程娜汁。 如果您通過 USB 連接了某個設(shè)備但該設(shè)備未在設(shè)備列表中列出,請確保您已啟用 USB 調(diào)試甥啄。
點擊 **MEMORY **時間線中的任意位置可打開 Memory Profiler存炮。
或者,您可以在命令行中使用 dumpsys 檢查您的應(yīng)用內(nèi)存,同時查看 logcat 中的 GC Event穆桂。
為什么應(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)確識別您的代碼在何處短時間分配了過多對象,或分配了泄漏的對象裁僧。
如需了解可減少應(yīng)用內(nèi)存使用的編程做法个束,請閱讀管理您的應(yīng)用內(nèi)存。
Memory Profiler 概覽
當(dāng)您首次打開 Memory Profiler 時聊疲,您將看到一條表示應(yīng)用內(nèi)存使用量的詳細(xì)時間線茬底,并可訪問用于強(qiáng)制執(zhí)行垃圾回收、捕捉堆轉(zhuǎn)儲和記錄內(nèi)存分配的各種工具获洲。
[圖片上傳中...(image-1dc2f9-1533109180179-4)]
圖 1. Memory Profiler
如圖 1 所示阱表,Memory Profiler 的默認(rèn)視圖包括以下各項:
- 用于強(qiáng)制執(zhí)行垃圾回收 Event 的按鈕。
- 用于捕獲堆轉(zhuǎn)儲的按鈕。
- 用于記錄內(nèi)存分配情況的按鈕最爬。 此按鈕僅在連接至運行 Android 7.1 或更低版本的設(shè)備時才會顯示涉馁。
- 用于放大/縮小時間線的按鈕。
- 用于跳轉(zhuǎn)至實時內(nèi)存數(shù)據(jù)的按鈕爱致。
- Event 時間線烤送,其顯示 Activity 狀態(tài)、用戶輸入 Event 和屏幕旋轉(zhuǎn) Event糠悯。
- 內(nèi)存使用量時間線帮坚,其包含以下內(nèi)容:
- 一個顯示每個內(nèi)存類別使用多少內(nèi)存的堆疊圖表,如左側(cè)的 y 軸以及頂部的彩色鍵所示互艾。
- 虛線表示分配的對象數(shù)试和,如右側(cè)的 y 軸所示。
- 用于表示每個垃圾回收 Event 的圖標(biāo)纫普。
不過灰署,如果您使用的是運行 Android 7.1 或更低版本的設(shè)備,則默認(rèn)情況下局嘁,并不是所有分析數(shù)據(jù)均可見溉箕。 如果您看到一條消息,其顯示“Advanced profiling is unavailable for the selected process”悦昵,則需要啟用高級分析以查看下列內(nèi)容:
- Event 時間線
- 分配的對象數(shù)
- 垃圾回收 Event
在 Android 8.0 及更高版本上肴茄,始終為可調(diào)試應(yīng)用啟用高級分析。
如何計算內(nèi)存
您在 Memory Profiler(圖 2)頂部看到的數(shù)字取決于您的應(yīng)用根據(jù) Android 系統(tǒng)機(jī)制所提交的所有私有內(nèi)存頁面數(shù)但指。 此計數(shù)不包含與系統(tǒng)或其他應(yīng)用共享的頁面寡痰。
[圖片上傳中...(image-a75add-1533109180178-3)]
圖 2. Memory Profiler 頂部的內(nèi)存計數(shù)圖例
內(nèi)存計數(shù)中的類別如下所示:
Java:從 Java 或 Kotlin 代碼分配的對象內(nèi)存。
-
Native:從 C 或 C++ 代碼分配的對象內(nèi)存棋凳。
即使您的應(yīng)用中不使用 C++拦坠,您也可能會看到此處使用的一些原生內(nèi)存,因為 Android 框架使用原生內(nèi)存代表您處理各種任務(wù)剩岳,如處理圖像資源和其他圖形時贞滨,即使您編寫的代碼采用 Java 或 Kotlin 語言。
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++ 中分配的對象。
當(dāng)連接至運行 Android 7.1 及更低版本的設(shè)備時奏属,此分配僅在 Memory Profiler 連接至您運行的應(yīng)用時才開始計數(shù)跨跨。 因此,您開始分析之前分配的任何對象都不會被計入囱皿。 不過勇婴,Android 8.0 附帶一個設(shè)備內(nèi)置分析工具,該工具可記錄所有分配嘱腥,因此耕渴,在 Android 8.0 及更高版本上,此數(shù)字始終表示您的應(yīng)用中待處理的 Java 對象總數(shù)齿兔。
與以前的 Android Monitor 工具中的內(nèi)存計數(shù)相比橱脸,新的 Memory Profiler 以不同的方式記錄您的內(nèi)存,因此分苇,您的內(nèi)存使用量現(xiàn)在看上去可能會更高些添诉。 Memory Profiler 監(jiān)控的類別更多,這會增加總的內(nèi)存使用量医寿,但如果您僅關(guān)心 Java 堆內(nèi)存栏赴,則“Java”項的數(shù)字應(yīng)與以前工具中的數(shù)值相似。
然而靖秩,Java 數(shù)字可能與您在 Android Monitor 中看到的數(shù)字并非完全相同须眷,這是因為應(yīng)用的 Java 堆是從 Zygote 啟動的,而新數(shù)字則計入了為它分配的所有物理內(nèi)存頁面沟突。 因此花颗,它可以準(zhǔn)確反映您的應(yīng)用實際使用了多少物理內(nèi)存。
注:目前惠拭,Memory Profiler 還會顯示應(yīng)用中的一些誤報的原生內(nèi)存使用量扩劝,而這些內(nèi)存實際上是分析工具使用的。 對于大約 100000 個對象求橄,最多會使報告的內(nèi)存使用量增加 10MB今野。 在這些工具的未來版本中,這些數(shù)字將從您的數(shù)據(jù)中過濾掉罐农。
查看內(nèi)存分配
內(nèi)存分配顯示內(nèi)存中每個對象是如何分配的。 具體而言催什,Memory Profiler 可為您顯示有關(guān)對象分配的以下信息:
- 分配哪些類型的對象以及它們使用多少空間涵亏。
- 每個分配的堆疊追蹤,包括在哪個線程中。
- 對象在何時被取消分配(僅當(dāng)使用運行 Android 8.0 或更高版本的設(shè)備時)气筋。
如果您的設(shè)備運行 Android 8.0 或更高版本拆内,您可以隨時按照下述方法查看您的對象分配: 只需點擊并按住時間線,并拖動選擇您想要查看分配的區(qū)域(如圖3 中所示)宠默。 不需要開始記錄會話麸恍,因為 Android 8.0 及更高版本附帶設(shè)備內(nèi)置分析工具,可持續(xù)跟蹤您的應(yīng)用分配搀矫。
如果您的設(shè)備運行 Android 7.1 或更低版本,則在 Memory Profiler 工具欄中點擊 Record memory allocations 瓤球。 記錄時融欧,Android Monitor 將跟蹤您的應(yīng)用中進(jìn)行的所有分配。 操作完成后卦羡,點擊 Stop recording 噪馏。
對于 Android 7.1 及更低版本,您必須顯式記錄內(nèi)存分配
在選擇一個時間線區(qū)域后(或當(dāng)您使用運行 Android 7.1 或更低版本的設(shè)備完成記錄會話時)绿饵,已分配對象的列表將顯示在時間線下方欠肾,按類名稱進(jìn)行分組,并按其堆計數(shù)排序拟赊。
注:在 Android 7.1 及更低版本上刺桃,您最多可以記錄 65535 個分配要门。 如果您的記錄會話超出此限值欢搜,則記錄中僅保存最新的 65535 個分配封豪。 (在 Android 8.0 及更高版本中,則沒有實際的限制炒瘟。)
要檢查分配記錄,請按以下步驟操作:
- 瀏覽列表以查找堆計數(shù)異常大且可能存在泄漏的對象缘琅。 為幫助查找已知類,點擊 Class Name 列標(biāo)題以按字母順序排序廓推。 然后點擊一個類名稱刷袍。 此時在右側(cè)將出現(xiàn) Instance View 窗格樊展,顯示該類的每個實例堆生,如圖 3 中所示淑仆。
- 在 Instance View 窗格中哥力,點擊一個實例。 此時下方將出現(xiàn) Call Stack 標(biāo)簽寞射,顯示該實例被分配到何處以及哪個線程中钞澳。
- 在 Call Stack 標(biāo)簽中,點擊任意行以在編輯器中跳轉(zhuǎn)到該代碼策治。
默認(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)用堆棧直秆。)
圖 4. 查看堆轉(zhuǎn)儲
要捕獲堆轉(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)存時間線下,顯示堆中的所有類類型宽堆,如圖 4 所示畜隶。
注:如果您需要更精確地了解轉(zhuǎn)儲的創(chuàng)建時間,可以通過調(diào)用 dumpHprofData()
在應(yīng)用代碼的關(guān)鍵點創(chuàng)建堆轉(zhuǎn)儲浸遗。
要檢查您的堆跛锌,請按以下步驟操作:
- 瀏覽列表以查找堆計數(shù)異常大且可能存在泄漏的對象届惋。 為幫助查找已知類盼樟,點擊 Class Name 列標(biāo)題以按字母順序排序。 然后點擊一個類名稱译秦。 此時在右側(cè)將出現(xiàn) Instance View 窗格击碗,顯示該類的每個實例稍途,如圖 5 中所示。
- 在 Instance View 窗格中突勇,點擊一個實例坷虑。此時下方將出現(xiàn) References迄损,顯示該對象的每個引用。
或者痊远,點擊實例名稱旁的箭頭以查看其所有字段,然后點擊一個字段名稱查看其所有引用冒版。 如果您要查看某個字段的實例詳情壤玫,右鍵點擊該字段并選擇 Go to Instance。 - 在 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)志表示。 (遺憾的是榄鉴,由于堆疊追蹤需要您執(zhí)行分配記錄牢硅,因此芝雪,您目前無法在 Android 8.0 上查看堆轉(zhuǎn)儲的堆疊追蹤惩系。)
在您的堆轉(zhuǎn)儲中,請注意由下列任意情況引起的內(nèi)存泄漏:
- 長時間引用 Activity抒抬、Context擦剑、View、Drawable 和其他對象赚抡,可能會保持對 Activity 或 Context 容器的引用纠屋。
- 可以保持 Activity 實例的非靜態(tài)內(nèi)部類售担,如 Runnable族铆。
- 對象保持時間超出所需時間的緩存。
在類列表中炫乓,您可以查看以下信息:
- 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)存大锌榻取(根據(jù) dominator 樹)授艰。
將堆轉(zhuǎn)儲另存為 HPROF
在捕獲堆轉(zhuǎn)儲后淮腾,僅當(dāng)分析器運行時才能在 Memory Profiler 中查看數(shù)據(jù)。 當(dāng)您退出分析會話時洲押,您將丟失堆轉(zhuǎn)儲诅诱。 因此送朱,如果您要保存堆轉(zhuǎn)儲以供日后查看驶沼,可通過點擊時間線下方工具欄中的 Export heap dump as HPROF file回怜,將堆轉(zhuǎn)儲導(dǎo)出到一個 HPROF 文件中换薄。 在顯示的對話框中轻要,確保使用 .hprof 后綴保存文件冲泥。
然后壁涎,通過將此文件拖到一個空的編輯器窗口(或?qū)⑵渫系轿募?biāo)簽欄中)怔球,您可以在 Android Studio 中重新打開該文件竟坛。
要使用其他 HPROF 分析器(如 jhat)钧舌,您需要將 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
分析內(nèi)存的技巧
使用 Memory Profiler 時,您應(yīng)對應(yīng)用代碼施加壓力并嘗試強(qiáng)制內(nèi)存泄漏歧匈。 在應(yīng)用中引發(fā)內(nèi)存泄漏的一種方式是件炉,先讓其運行一段時間斟冕,然后再檢查堆磕蛇。 泄漏在堆中可能逐漸匯聚到分配頂部十办。 不過向族,泄漏越小炸枣,您越需要運行更長時間的應(yīng)用才能看到泄漏。
您還可以通過以下方式之一觸發(fā)內(nèi)存泄漏:
- 將設(shè)備從縱向旋轉(zhuǎn)為橫向霍衫,然后在不同的 Activity 狀態(tài)下反復(fù)操作多次敦跌。 旋轉(zhuǎn)設(shè)備經(jīng)常會導(dǎo)致應(yīng)用泄漏 Activity柠傍、Context 或 View 對象惧笛,因為系統(tǒng)會重新創(chuàng)建 Activity,而如果您的應(yīng)用在其他地方保持對這些對象之一的引用拜效,系統(tǒng)將無法對其進(jìn)行垃圾回收紧憾。
- 處于不同的 Activity 狀態(tài)時赴穗,在您的應(yīng)用與另一個應(yīng)用之間切換(導(dǎo)航到主屏幕般眉,然后返回到您的應(yīng)用)潜支。