android 如何分析應用的內存(十七)——使用MAT查看Android堆

android 如何分析應用的內存(十七)——使用MAT查看Android堆

前一篇文章,介紹了使用Android profiler中的memory profiler來查看Android的堆情況。
如Android 堆中有哪些對象,這些對象的引用情況是什么樣子的。

可是我們依然面臨一個比較嚴峻的挑戰:不管是app開發者,還是內存分析者而言,堆中的對象,非常之多,不僅有Android 原生的類,還有第三方庫使用的類。這些類在使用過程中,也可能因為有較大的shallow size 或者retained size而混淆內存的分析。

為了解決這樣的問題,我們更希望,通過不同時間點的堆,進行差分比較。即在時刻t1生成的堆heap1和t2時刻生成的堆heap2進行相互比較。

為此,我們將介紹java開發中重要的內存分析工具MAT。

MAT使用前的準備

在上一篇文章中,我們使用AS捕獲了堆,現在我們需要將其導出,用在MAT工具上。如下圖:
在這里插入圖片描述

接下來將Android保存的heap dump進行格式轉換,以滿足MAT的需求。轉換格式的工具在Android SDK中。如下:

/Users/biaowan/Library/Android/sdk/platform-tools/hprof-conv ./mat/memory-test_malloc_int\[\].hprof mat_test1.hprof

在這里插入圖片描述

MAT的使用

打開MAT之后,進入菜單欄->File->Open File。然后選擇剛才轉換之后的mat_test.hprof文件。如下圖
在這里插入圖片描述

可見,主界面顯示一個overview的界面,該界面用英文詳細表述了具體細節,不在贅述。下面解釋上圖的八個標記。

  • 標記1:打開overview 界面。即上面的主界面。

  • 標記2:打開當前堆中的對象分布情況,默認按照類名進行排序。右鍵可以進行相應操作,各個操作什么意思,已經標明。如下圖
    在這里插入圖片描述

  • 標記3:顯示本heap中的所有dominator tree(注意:dominator tree,已經在上一篇文章中介紹:android 如何分析應用的內存(十六)——使用AS查看Android堆:http://t.csdn.cn/GTWpR). 而各個對象應該怎么查看其對應的dominator tree。見標記2對應的右鍵說明。

  • 標記4:Open Object Qurey Language,類似于使用SQL語句進行查詢。因為MAT提供的菜單功能已經完全夠Android使用,因此本文不再介紹

  • 標記5:展示線程的名字,堆棧,本地變量等。但是Android 沒有提供這個功能,因此無法使用

  • 標記6:打印各種報告,如下圖標記
    在這里插入圖片描述

  • 標記7:即為標記2中,右鍵支持的各種操作,詳見標記2

  • 標記8:搜索按鈕,可以按照地址進行搜索

為了能夠詳細說明,如何操作MAT,下文將會以各種問題作為模板,詳細介紹操作過程

問題1:如何查看某個類有哪些對象

  1. 點擊標記1,打開所有類的列表。
  2. 在第一行,鍵入需要查找的類,或者按照不同的大小進行排序和過濾
  3. 選中類,然后點擊右鍵,選擇List Objects.然后按照需求列出各個對象
    在這里插入圖片描述

問題2:如何查看某個對象到GC root的引用鏈

  1. 選中某個對象,右鍵選中Paths to GC root
  2. 再次選中exclude all xxx references
    在這里插入圖片描述

可見整個引用鏈清晰明了,不在繪圖說明

問題3:如何查看對象的Dominator tree(支配樹)

  1. 選中對象,右鍵選擇Java Basics
  2. 再次選中Open in Dominator tree
  3. 在彈出的框中,選擇finish。默認以對象排序
    在這里插入圖片描述

從圖中可以看到TaskRunable對象直接支配兩個對象,一個int數組,一個弱引用

問題4:如何查看一個對象的直接支配者

  1. 選中對象,然后右鍵,選擇immediate dominator
  2. 在彈出框中,選擇finish
    在這里插入圖片描述

可以看到我們選中的TaskRunable對象的直接支配者是一個Task對象

問題5:如何查看類加載器,是否重復加載同一個類

  1. 點擊標記1,打開overview界面
  2. 滾動界面到最底下
  3. 選擇Duplicate classes
    在這里插入圖片描述

問題6:如何查看堆中,最占內存的部分

  1. 點擊標記1,打開overview界面
  2. 滾動至最底下
  3. 選擇Top cosumer
    在這里插入圖片描述

從圖中可以看到,分別按照對象,類,類加載器,包名列出了最占內存的部分

問題7:如何查看堆的報告

  1. 點擊標記6.選擇Heap dump overview
  2. 在對報告中,點擊table of content 查看內容表(該字段,在報告的底部)
    在這里插入圖片描述

從中也可以直接查看最占內存的對象

問題8:如何進行泄露檢查

  1. 點擊標記6,選擇Leak Suspect
    在這里插入圖片描述

從圖中可以看到,有三個懷疑的對象,往下滾動,可以看到三個懷疑對象的詳細細節,如下
在這里插入圖片描述

圖中,簡要說明了Task類,有2100個實例,占了29.51%的內容。點擊details它會顯示相應的引用鏈路徑。可清晰看到GC root的整個引用鏈。

多個Heap進行差分分析,查找內存問題

為了一步步演練,如何使用多個heap進行差分分析,我們選擇上一篇文章方案2中的例子:android 如何分析應用的內存(十六)——使用AS查看Android堆:http://t.csdn.cn/JYGFC。然后在同一個進程的兩個不同時刻,分別選取不同的heap,分別叫as_heap1.hprof和as_heap2.hprof.

場景1:MAT 自動分析兩個堆之間的內存泄露

  1. 按照上文提及的hprof-conv工具,將as_heap1.hprof,as_heap2.hprof分別轉換為mat_heap1.hprof,mat_heap2.hprof。然后用mat工具將其打開。

  2. 打開第二個heap的overvie操作欄,即標記1。滾動到最底部

  3. 選擇Leak suspects by Snapshot comparision.

  4. 在彈出的框中,選擇mat_heap1.hprof。然后點擊finish。讓mat_heap2.hprof與mat_heap1.hprof做差分分析,然后給出一個報告,如下(需要等待一段時間)
    在這里插入圖片描述
    在這里插入圖片描述

從圖中可以看到,懷疑com.example.test_malloc.Task對象泄露,它有4900個對象,占整個堆的49.26%。點擊details可以看到這個引用鏈,如下圖
在這里插入圖片描述

從圖中可以看到,Task被DeviceManager的listener所持有,導致GC無法回收。所以找到了內存泄露點。

場景2:無法自動分析時,手動分析

當兩個heap堆,間隔時間較短,泄露的對象,占據整個堆的空間較小,此時mat無法進行自動分析。此時我們可以手動分析。

接下來,我們用時間間隔較小的兩個堆,分別叫mat_heap3.hprof和mat_heap4.hprof

注意:mat_heap3.hprof和mat_heap4.hprof是用AS 重新抓取的時間間隔較近的兩個堆

  1. 用mat打開mat_heap3.hprof,和mat_heap4.hprof

  2. 按照問題6,輸出消耗內存最大的部分。下面是mat_heap3.hprof的報告。
    在這里插入圖片描述

從中,我們看到,占據內存最大的首要對象是int數組。接下來我們手動分析兩個堆中的int數組之間的差距——即mat_heap4.hprof比mat_heap3.hprof多了哪幾個int數組

  1. 點擊mat_heap3.hprof的統計信息,即標記2.然后選中int[]。右鍵列出所有的對象。如下圖
    在這里插入圖片描述

  2. 點擊操作歷史記錄欄,右鍵list_objects… 然后點擊add to compare basket。如下圖
    在這里插入圖片描述

  3. 因為我們需要比較兩個heap堆的int[]情況,因此選中mat_heap4.hprof之后,按照步驟3,4做同樣操作。將會在compare basket窗口兩個需要比較的對象。然后點擊感嘆號,開始比較即可。如下:
    在這里插入圖片描述

對測試結果,進行簡單排序,shallow_heap #1 升序排列。即可展示heap3中沒有而heap4中具有的對象。這也是從抓取heap3時刻,到抓取heap4時刻之間,堆中多出來的int數組對象。為前排的10個對象。

按照前文的問題2即可查看其引用鏈,從而分析被誰持有,為何沒有被釋放掉。

在第2步中,輸出的top comsumer除了int數組以外,還有其他的對象,因此按照步驟3,4,5即可進行兩個堆的比較。我們已經以int[]為例子,做了詳細說明,就不再一一比較。

除了使用top comsumer輔助定位需要比較的對象以外,還可以對任何懷疑的對象進行比較。步驟完全相同。

至此,MAT的使用介紹完畢。

MAT彌補了AS在內存分析上的如下不足:

  • 無法自定義Retained Set(這對于大型應用很有用)
  • 無法進行地址查找
  • 無法進行堆之間的比較
  • 無法按照需要進行排序
  • 無法按照需要進行過濾等

雖然MAT已經足夠強大,但是依然還有一個內存問題,懸而未決——怎么才能知道這些內存泄露是由哪一個線程觸發,它們又有怎樣的調用棧?

在多線程編程中,對象的泄露,即可能是對象之間的引用不合理,也可能是線程之間的邏輯不合理,如生產線程和消費線程不夠合理等等。MAT無法解決Android線程所帶來的內存泄露。

接下里,請期待如何用工具找到這種多線程帶來的內存泄露。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/36126.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/36126.shtml
英文地址,請注明出處:http://en.pswp.cn/news/36126.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【ArcGIS】經緯度數據轉化成平面坐標數據

將點位置導入Gis中,如下(經緯度表征位置): 如何利用Gis將其轉化為平面坐標呢? Step1 坐標變換 坐標變換,打開ArcToolbox,找到“數據管理工具”->“投影和變換”->“要素”->“投影”…

MySQL—緩存

目錄標題 為什么要有Buffer Poolbuffer pool有多大buffer pool緩存什么 如何管理Buffer Pool如何管理空閑頁如何管理臟頁如何提高緩存命中率預讀失效buffer pool污染 臟頁什么時候會被刷入到磁盤 為什么要有Buffer Pool 雖然說MySQL的數據是存儲在磁盤中,但是也不能…

抖音關鍵詞搜索小程序排名怎么做

抖音關鍵詞搜索小程序排名怎么做 1 分鐘教你制作一個抖音小程序。 抖音小程序就是我的視頻,左下方這個藍色的鏈接,點進去就是抖音小程序。 如果你有了這個小程序,發布視頻的時候可以掛載這個小程序,直播的時候也可以掛載這個小…

Express 實戰(一):概覽

在正式學習 Express 內容之前,我們有必要從大的方面了解一下 Node.js 。 在很長的一段時間里,JavaScript 一門編寫瀏覽器中運行腳本的語言。不過近些年,隨著互聯網的發展以及技術進步,JavaScript 迎來了一個集中爆發的時代。一個…

谷歌關閉跨域限制.(生成一個開發瀏覽器),Chrome關閉跨域

(一)、首先找到瀏覽器在電腦磁盤中的位置,并復制 (二)、復制一個瀏覽器的快捷方式到桌面(不影響正常瀏覽器) (三)、chrom鼠標右鍵屬性,修改快捷方式的目標 (四)chrome.exe 后面添加 --disable-web-security --user-data-dir 復制的Chrome瀏覽…

787. 歸并排序

文章目錄 QuestionIdeasCode Question 給定你一個長度為 n 的整數數列。 請你使用歸并排序對這個數列按照從小到大進行排序。 并將排好序的數列按順序輸出。 輸入格式 輸入共兩行,第一行包含整數 n 。 第二行包含 n 個整數(所有整數均在 1~109 范圍…

JUC并發編程(JUC核心類、TimeUnit類、原子操作類、CASAQS)附帶相關面試題

目錄 1.JUC并發編程的核心類 2.TimeUnit(時間單元) 3.原子操作類 4.CAS 、AQS機制 1.JUC并發編程的核心類 雖然java中的多線程有效的提升了程序的效率,但是也引發了一系列可能發生的問題,比如死鎖,公平性、資源管理…

【100天精通python】Day34:使用python操作數據庫_ORM(SQLAlchemy)使用

目錄 專欄導讀 1 ORM 概述 2 SQLAlchemy 概述 3 ORM:SQLAlchemy使用 3.1 安裝SQLAlchemy: 3.2 定義數據庫模型類: 3.3 創建數據表: 3.4 插入數據: 3.5 查詢數據: 3.6 更新數據: 3.7 刪…

C/C++中volatile關鍵字詳解

1. 為什么用volatile? C/C 中的 volatile 關鍵字和 const 對應,用來修飾變量,通常用于建立語言級別的 memory barrier。這是 BS 在 "The C Programming Language" 對 volatile 修飾詞的說明: A volatile specifier is a hint to a…

【Git】 git push origin master Everything up-to-date報錯

hello,我是索奇,可以叫我小奇 git push 出錯?顯示 Everything up-to-date 那么看看你是否提交了message 下面是提交的簡單流程 git add . git commit -m "message" git push origin master 大多數伙伴是沒寫git commit -m "…

AI自動駕駛

AI自動駕駛 一、自動駕駛的原理二、自動駕駛的分類三、自動駕駛的挑戰四、自動駕駛的前景五、關鍵技術六、自動駕駛的安全問題七、AI數據與自動駕駛八、自動駕駛的AI算法總結 自動駕駛技術是近年來備受關注的熱門話題。它代表了人工智能和機器學習在汽車行業的重要應用。本文將…

UML之四種事物

目錄 結構事物 行為事物 分組事物: 注釋事物 結構事物 1.類(Class) -類是對一組具有相同屬性、方法、關系和語義的對象的描述。一個類實現一個或多個接口 2.接口(interface) -接口描述 了一個類或構件的一個服務的操作集。接口僅僅是定義了一組操作的規范&…

案例16 基于Spring Boot實現學生新增案例

基于Spring Boot實現學生新增。 1. 創建Spring Boot項目 創建Spring Boot項目&#xff0c;項目名稱為case16-springboot-student01。 ? 2. 設置項目信息 ? 3. 選擇依賴 選擇Lombok ? 選擇Spring Web ? 4. 設置項目名稱 ? 5. Maven依賴 <?xml version"1.0&qu…

Nature子刊 |腸道宏病毒組揭示百歲老人長壽秘訣

發表期刊&#xff1a;nature microbiology 發表時間&#xff1a;2023 影響因子&#xff1a;28.3 DOI: 10.1038/s41564-023-01370-6 研究背景 衰老是一種不可逆轉的自然過程&#xff0c;隨著年齡的增長&#xff0c;機體諸多方面出現功能性下降&#xff0c;與衰老相關的疾病&a…

生成式AI顛覆傳統數據庫的十種方式

對于生成式AI的所有閃光點&#xff0c;這個新時代最大的轉變可能深埋在軟件堆棧中。AI算法正在不易覺察地改變一個又一個數據庫。他們正在用復雜、自適應且看似更直觀的AI新功能顛覆傳統數據庫。 目錄 1、向量和嵌入 2、查詢模型 3、建議 4、索引范例 5、數據分類 6、更…

Unity 框架學習--1

由淺入深&#xff0c;慢慢演化實現框架 兩個類的實現代碼完全一樣&#xff0c;就只有類名或類型不一樣的時候&#xff0c;而且還需要不斷擴展&#xff08;未來會增加各種事件&#xff09;的時候&#xff0c;這時候就用 泛型 繼承 來提取&#xff0c;繼承解決擴展的問題&#…

【RabbitMQ與SpringBoot集成測試收發消息】

【RabbitMQ與SpringBoot集成測試收發消息】 一、環境說明二、實驗步驟三、小結 一、環境說明 安裝環境&#xff1a;虛擬機VMWare Centos7.6 Maven3.6.3 JDK1.8RabbitMQ版本&#xff1a;rabbitmq-server-3.8.8-1.el7.noarch.rpm編程工具Idea 運行JDK為17 二、實驗步驟 在Rab…

List和數組互轉方法以及踩坑點

一、數組轉List 1. 使用for循環逐個添加 String[] arr {"A", "B", "C"}; List<String> list new ArrayList<>(); for (String element : arr) {list.add(element); }2. 使用Arrays.asList(arr) String[] arr {"A", …

TypeScript 泛型的深入解析與基本使用

系列文章目錄 文章目錄 系列文章目錄前言一、泛型的概念二、泛型函數三、泛型類四、泛型接口五、泛型約束總結前言 泛型是TypeScript中的一個重要概念,它允許我們在定義函數、類或接口時使用參數化類型,增強了代碼的靈活性和重用性。本文將深入探討泛型的概念,以及如何在Ty…

智能駕駛系列報告之一:智能駕駛 ChatGPT時刻有望來臨

原創 | 文 BFT機器人 L3 功能加速落地&#xff0c;政策標準有望明確 L2 發展日益成熟&#xff0c;L3 功能加速落地。根據市場監管總局發布的《汽車駕駛自動化分級》與 SAE發布的自動駕駛分級標準&#xff0c;自動駕駛主要分為 6 個級別&#xff08;0 級到 5 級&#xff0c;L0 …