Memory Profiler是Android Profiler中的一個組件,它能夠幫助您識別內存泄漏和可能致使卡頓、凍結甚至應用程序崩潰的內存抖動。它顯示一個應用程序內存使用的實時圖表,並容許你抓取堆棧信息、強行垃圾收集和跟蹤內存分配。html
要打開Memory Profiler,請執行如下步驟:android
Android提供了一個託管內存環境,當它肯定應用程序再也不使用某些對象時,垃圾收集器會將未使用的內存釋放回堆中。Android尋找未使用內存的方式正在不斷改進,但在全部Android版本中,系統必須短暫暫停代碼。大多數時候,停頓是不被感知的。可是,若是應用程序分配內存的速度快於系統回收內存的速度,則應用程序可能會發生延遲,等待回收器釋放足夠的內存以知足分配。延遲可能致使應用程序發生跳幀並致使明顯變慢。正則表達式
即便你的應用程序並無表現出緩慢,但若是它泄露了內存,即便運行在後臺也能夠佔用內存。此行爲會致使垃圾回收事件被強制執行,從而下降系統的其他內存性能。最後,系統可能被迫終止應用程序進程以回收內存。所以當用戶返回到此應用程序時,它必須徹底從新啓動。api
爲了幫助防止這些問題,您應該經過如下操做使用Memory Profiler進行檢查:瀏覽器
當您第一次打開Memory Profiler時,您將看到應用程序的內存使用的詳細時間軸,和可使用的內存工具包括強制垃圾回收、抓取堆信息和記錄內存分配。緩存
如上圖所示,Memory Profiler的默認視圖包括如下內容:session
內存使用時間軸,包括如下內容:app
可是,若是您使用的是運行Android 7.1或更低版本的設備,默認狀況下並不是全部分析數據均可見。若是您看到一條消息,上面寫着「Advanced profiling is unavailable for the selected process」,則須要啓用高級分析才能看到如下內容:框架
在Android 8.0及更高版本上,高級分析在可調試的應用程序上始終開啓。jvm
你在Memory Profiler頂部看到的數字基於您的應用經過Android 系統提交的全部私有內存頁面。此計數不包括與系統或其餘應用程序共享的頁面。
內存計數中的類別以下:
與以前Android Monitor中內存工具的計數相比,新的Memory Profiler以不一樣的方式記錄您的內存。於是,內存使用率看起來會更高了。Memory Profiler監視一些額外的類別,這些類別增長了總的內存。可是若是您只關心Java堆內存,那麼「Java」數值應該與前一個工具中的值相似。可是Java數值可能與您在Android Monitor中看到的不徹底匹配,新數值統計了自從Zygote派生以來應用程序的Java堆分配的全部物理頁面。所以,它提供了應用程序實際使用的物理內存量的精確表示。
注意:使用搭載 Android 8.0(API 級別 26)及更高版本的設備時,Memory Profiler 還會顯示應用中的一些誤報的原生內存使用量,而這些內存其實是分析工具使用的。對於大約 100000 個對象,最多會使報告的內存使用量增長 10MB。在 IDE 的將來版本中,這些數字將從您的數據中過濾掉。
內存分配向您展現了內存中的每一個Java對象和JNI引用是如何分配。具體來講,Memory Profiler能夠向您顯示如下有關對象分配的信息:
若是您的設備運行的是Android 8.0或更高版本,您能夠隨時查看對象分配,以下所示:在時間軸中拖動以選擇要查看分配的區域。不須要開始錄製會話,由於Android8.0及更高版本包含一個設備內置分析工具,能夠不斷跟蹤應用程序的分配。詳細內容能夠參考視頻:高版本查看內存分配
若是您的設備運行的是Android 7.1或更低版本,請單擊Memory Profiler工具欄中的Record memory allocations圖標。錄製時,Memory Profiler會跟蹤應用程序中發生的全部分配。完成後,單擊Stop recording圖標以查看分配。詳細內容能夠參考視頻:低版本查看內存分配
選擇時間線的某個區域後(或在使用運行Android7.1或更低版本的設備完成錄製會話時),已分配對象的列表將顯示在時間線下方,按類名分組並按堆計數排序。
注意:在 Android 7.1 及更低版本上,您最多能夠記錄 65535 個分配。若是您的記錄會話超出此限制,則記錄中僅保存最新的 65535 個分配。(在 Android 8.0 及更高版本上,則沒有實際的限制。)
要檢查分配記錄,請執行如下步驟:
您可使用已分配對象列表上方的兩個菜單來選擇要檢查的堆以及如何組織數據。
從左側的菜單中,選擇要檢查的堆:
從右側的菜單中,選擇如何組織分配:
爲了提升分析時的應用程序性能,默認狀況下,內存探查器按期對內存分配進行採樣。在運行API級別26或更高級別的設備上測試時,可使用Allocation Tracking下拉列表更改此行爲。可用選項以下:
注意:默認狀況下,Android Studio在執行CPU錄製時中止跟蹤實時分配,並在CPU錄製完成後將其從新打開。您能夠在「CPU記錄配置」對話框中更改此行爲。
Java Native Interface(JNI)是一個容許Java代碼和Native代碼相互調用的框架。JNI引用是由Native代碼進行管理的,所以Native代碼使用的Java對象可能會存活很長時間。若是在沒有顯式刪除JNI引用的狀況下丟棄JNI引用,Java堆上的某些對象可能會變得不可訪問。此外,還可能會耗盡全局JNI引用的限制。要解決此類問題,請使用Memory Profiler中的JNI heap來瀏覽全部全局JNI引用,並按Java類型和Native調用堆棧篩選它們。有了這些信息,您能夠找到什麼時候何地建立和刪除全局JNI引用。
當應用程序運行時,選擇要檢查的時間軸的一部分,而後從類列表上方的下拉菜單中選擇JNI heap。接下來,您就能夠像往常同樣檢查堆中的對象,並雙擊Allocation Call Stack選項卡中的對象,查看在代碼中JNI引用的分配和釋放的位置,以下圖所示。
要檢查應用程序JNI代碼的內存分配,必須將應用程序部署到運行Android 8.0或更高版本的設備上。
堆信息能顯示在抓取堆信息時應用程序中的哪些對象正在使用內存。特別是在長時間的用戶會話以後,經過分析堆信息中是否存在您認爲不該該存在的對象,能夠用來幫助識別內存泄漏。抓取堆信息後,你能夠查看如下內容:
要抓取堆信息,請單擊Memory Profiler工具欄中的Dump Java heap圖標。在抓取期間,Java內存量可能會臨時增長。這是正常的,由於堆抓取發生在與應用程序相同的進程中,須要一些內存來收集數據。堆信息在內存時間軸的下方,顯示堆中全部類的類型,以下圖所示。
若是須要更精確地瞭解堆的抓取時間,能夠經過調用dumpHprofData()在應用程序代碼的關鍵點抓取堆信息。
在類列表中,能夠看到如下信息:
您可使用已分配對象列表上方的兩個菜單來選擇要檢查的堆信息以及如何組織數據。
從左側的菜單中,選擇要檢查的堆:
從右側的菜單中,選擇如何組織分配:
默認狀況下,列表按Retained Size列排序。若要按其餘列中的值排序,請單擊該列的標題。
單擊類名打開右側的IInstance View窗口(以下圖所示),每一個列出的實例包括如下內容:
注意:默認狀況下,堆信息不會向您顯示每一個已分配對象的堆棧軌跡。要獲取堆棧軌跡,在點擊 Dump Java heap 以前,您必須先開始記錄內存分配。而後,您能夠在 Instance View 中選擇一個實例,並查看 References 標籤旁邊的 Call Stack 標籤,以下圖所示。不過,在您開始記錄分配以前,可能已分配一些對象,所以不會顯示這些對象的調用堆棧。在包含調用堆棧的實例在圖標上會有一個「堆棧」標誌表示。(遺憾的是,因爲堆棧軌跡須要您執行分配記錄,所以您目前沒法在 Android 8.0 上查看堆信息的堆棧軌跡。)
要檢查堆信息,請執行如下步驟:
在堆信息中,注意如下狀況可能致使的內存泄漏:
捕獲堆信息後,只有在Profiler運行時,數據才能在Memory Profiler中查看。退出剖析會話時,將丟失堆數據。所以,若是您想保存它以便之後查看,請將堆信息導出到HPROF文件。在Android Studio 3.1及更低版本中,Export capture to file按鈕位於時間軸下的工具欄左側;在Android studio 3.2及更高版本中,Sessions窗格中每一個Heap Dump的右側都有一個Export Heap Dump按鈕。在彈出的Export As對話框中,使用.hprof文件擴展名保存文件。
要使用不一樣的HPROF分析器(如jhat),須要將HPROF文件從Android格式轉換爲Java SE HPROF格式。您可使用android_sdk/platform tools/目錄中提供的hprof-conv
工具來執行此操做。使用兩個參數(原始hprof文件的位置和轉換後的hprof文件的寫入位置)運行hprof-conv
命令。例如:
hprof-conv heap-original.hprof heap-converted.hprof
要導入HPROF(.hprof)文件,請單擊Sessions窗格中的Start a new profiling session圖標,選擇Load from file,而後從文件瀏覽器中選擇該文件。也能夠經過將HPROF文件從文件瀏覽器拖動到編輯器窗口中來導入該文件。
在使用Memory Profiler時,您應該給應用程序代碼增長壓力,試圖去暴露內存泄漏。引起應用程序內存泄漏的一種方法是在檢查堆以前讓它運行一段時間,泄漏可能會逐漸聚集到堆中分配的頂部。可是當泄漏越小時,應用程序就須要運行越長時間,再進行泄漏檢查。
您還能夠經過如下方式之一觸發內存泄漏:
參考文檔: