envi 文件 生成mat_JVM 内存分析工具 MAT 的深度讲解与实践——入门篇
1. MAT 工具簡介
MAT(全名:Memory Analyzer Tool),是一款快速便捷且功能強(qiáng)大豐富的 JVM 堆內(nèi)存離線分析工具。其通過展現(xiàn) JVM 異常時(shí)所記錄的運(yùn)行時(shí)堆轉(zhuǎn)儲(chǔ)快照(Heap dump)狀態(tài)(正常運(yùn)行時(shí)也可以做堆轉(zhuǎn)儲(chǔ)分析),幫助定位內(nèi)存泄漏問題或優(yōu)化大內(nèi)存消耗邏輯。
1.1 MAT 使用場景及主要解決問題
場景一:內(nèi)存溢出,JVM堆區(qū)或方法區(qū)放不下存活及待申請的對象。如:高峰期系統(tǒng)出現(xiàn) OOM(Out of Memory)異常,需定位內(nèi)存瓶頸點(diǎn)來指導(dǎo)優(yōu)化。
場景二:內(nèi)存泄漏,不會(huì)再使用的對象無法被垃圾回收器回收。如:系統(tǒng)運(yùn)行一段時(shí)間后出現(xiàn) Full GC,甚至周期性 OOM 后需人工重啟解決。
場景三:內(nèi)存占用高。如:系統(tǒng)頻繁 GC ,需定位影響服務(wù)實(shí)時(shí)性、穩(wěn)定性、吞吐能力的原因。
1.2 基礎(chǔ)概念
1.2.1 Heap Dump
Heap Dump 是 Java 進(jìn)程堆內(nèi)存在一個(gè)時(shí)間點(diǎn)的快照,支持 HPROF 及 DTFJ 格式,前者由 Oracle 系列 JVM 生成,后者是 IBM 系列 JVM 生成。其內(nèi)容主要包含以下幾類:
- 所有對象的實(shí)例信息:對象所屬類名、基礎(chǔ)類型和引用類型的屬性等。
- 所有類信息:類加載器、類名、繼承關(guān)系、靜態(tài)屬性等。
- GC Root:GC Root 代表通過可達(dá)性分析來判定 JVM 對象是否存活的起始集合。JVM 采用追蹤式垃圾回收(Tracing GC)模式,從所有 GC Roots 出發(fā)通過引用關(guān)系可以關(guān)聯(lián)的對象就是存活的(且不可回收),其余的不可達(dá)的對象(Unreachable object:如果無法從 GC Root 找到一條引用路徑能到達(dá)某對象,則該對象為Unreachable object)可以回收。
- 線程棧及局部變量:快照生成時(shí)刻的所有線程的線程棧幀,以及每個(gè)線程棧的局部變量。
1.2.2 Shallow Heap
Shallow Heap 代表一個(gè)對象結(jié)構(gòu)自身所占用的內(nèi)存大小,不包括其屬性引用對象所占的內(nèi)存。如 java.util.ArrayList 對象的 Shallow Heap 包含8字節(jié)的對象頭、8字節(jié)的對象數(shù)組屬性 elementData 引用 、 4字節(jié)的 size 屬性、4字節(jié)的 modCount 屬性(從 AbstractList 繼承及對象頭占用內(nèi)存大小),有的對象可能需要加對齊填充但 ArrayList 自身已對齊不需補(bǔ)充,注意不包含 elementData 具體數(shù)據(jù)占用的內(nèi)存大小。
1.2.3 Retained Set
一個(gè)對象的 Retained Set,指的是該對象被 GC 回收后,所有能被回收的對象集合(如下圖所示,G的 Retain Set 只有 G 并不包含 H,原因是雖然 H 也被 G 引用,但由于 H 也被 F 引用 ,G 被垃圾回收時(shí)無法釋放 H);另外,當(dāng)該對象無法被 GC 回收,則其 Retained set 也必然無法被 GC 回收。
1.2.4 Retained Heap
Retained Heap 是一個(gè)對象被 GC 回收后,可釋放的內(nèi)存大小,等于釋放對象的 Retained Heap 中所有對象的 Shallow Heap 的和(如下圖所示,E 的 Retain Heap 就是 G 與 E 的 Shallow Heap 總和,同理不包含 H)。
1.2.5 Dominator tree
如果所有指向?qū)ο?Y 的路徑都經(jīng)過對象 X,則 X 支配(dominate) Y(如下圖中,C、D 均支配 F,但 G 并不支配 H)。Dominator tree 是根據(jù)對象引用及支配關(guān)系生成的整體樹狀圖,支配樹清晰描述了對象間的依賴關(guān)系,下圖左的 Dominator tree 如下圖右下方支配樹示意圖所示。支配關(guān)系還有如下關(guān)系:
- Dominator tree 中任一節(jié)點(diǎn)的子樹就是被該節(jié)點(diǎn)支配的節(jié)點(diǎn)集合,也就是其 Retain Set。
- 如果 X 直接支配 Y,則 X 的所有支配節(jié)點(diǎn)均支配 Y。
1.2.6 OQL
OQL 是類似于 SQL 的 MAT 專用統(tǒng)一查詢語言,可以根據(jù)復(fù)雜的查詢條件對 dump 文件中的類或者對象等數(shù)據(jù)進(jìn)行查詢篩選。
1.2.7 references
outgoing references、incoming references 可以直擊對象間依賴關(guān)系,MAT 也提供了鏈?zhǔn)娇焖俨僮鳌?/p>
- outgoing references:對象引用的外部對象(注意不包含對象的基本類型屬性。基本屬性內(nèi)容可在 inspector 查看)。
- incoming references:直接引用了當(dāng)前對象的對象,每個(gè)對象的 incoming references 可能有 0 到多個(gè)。
2. MAT 功能概述及對比
2.1 MAT 功能概述
注:MAT 的產(chǎn)品能力非常豐富,本文簡要總結(jié)產(chǎn)品特性幫大家了解全貌,在下一篇文章《JVM 內(nèi)存分析實(shí)戰(zhàn)進(jìn)階篇——核心功能及應(yīng)用場景》中,會(huì)詳細(xì)展開介紹各項(xiàng)核心功能的場景、案例、最佳實(shí)踐等。
MAT 的工作原理是對 dump 文件建立多種索引,并基于索引來實(shí)現(xiàn) [1]內(nèi)存分布、[2]對象間依賴(如實(shí)體對象引用關(guān)系、線程引用關(guān)系、ClassLoader引用關(guān)系等)、[3]對象狀態(tài)(內(nèi)存占用量、字段屬性值等)、[4]條件檢索(OQL、正則匹配查詢等)這四大核心功能,并通過可視化展現(xiàn)輔助 Developer 精細(xì)化了解 JVM 堆內(nèi)存全貌。
2.1.1 內(nèi)存分布
- 全局概覽信息:堆內(nèi)存大小、對象個(gè)數(shù)、類的個(gè)數(shù)、類加載器的個(gè)數(shù)、GC root 個(gè)數(shù)、線程概況等全局統(tǒng)計(jì)信息。
- Dominator tree:按對象的 Retain Heap 排序,也支持按多個(gè)維度聚類統(tǒng)計(jì),最常用的功能之一。
- Histogram:羅列每個(gè)類實(shí)例的內(nèi)存占比,包括自身內(nèi)存占用量(Shallow Heap)及支配對象的內(nèi)存占用量(Retain Heap),支持按 package、class loader、super class、class 聚類統(tǒng)計(jì),最常用的功能之一。
- Leak Suspects:直擊引用鏈條上占用內(nèi)存較多的可疑對象,可解決一些基礎(chǔ)問題,但復(fù)雜的問題往往幫助有限。
- Top Consumers:展現(xiàn)哪些類、哪些 class loader、哪些 package 占用最高比例的內(nèi)存。
2.1.2 對象間依賴
- References:提供對象的外部引用關(guān)系、被引用關(guān)系。通過任一對象的直接引用及間接引用詳情(主要是屬性值及內(nèi)存占用),進(jìn)而提供完善的依賴鏈路詳情。
- Dominator tree:支持按對象的 Retain Heap 排序,并提供詳細(xì)的支配關(guān)系,結(jié)合 references 可以實(shí)現(xiàn)大對象快速關(guān)聯(lián)分析;
- Thread overview:展現(xiàn)轉(zhuǎn)儲(chǔ) dump 文件時(shí)線程棧幀等詳細(xì)狀態(tài),也提供各線程的 Retain Heap 等關(guān)聯(lián)內(nèi)存信息。
- Path To GC Roots:提供任一對象到GC Root的鏈路詳情,幫助了解不能被 GC 回收的原因。
2.1.3 對象狀態(tài)
- 最核心的是通過 inspector 面板提供對象的屬性信息、類繼承關(guān)系信息等數(shù)據(jù),協(xié)助分析內(nèi)存占用高與業(yè)務(wù)邏輯的關(guān)系。
- 集合狀態(tài)的檢測,如:通過 ArrayList 或數(shù)組的填充率定位空集合空數(shù)組造成的內(nèi)存浪費(fèi)、通過 HashMap 沖突率判定 hash 策略是否合理等。
2.1.4 按條件檢索對象
- OQL:提供一種類似于SQL的對象(類)級別統(tǒng)一結(jié)構(gòu)化查詢語言。如:查找 size=0 且未使用過的 ArrayList: select * from java.util.ArrayList where size=0 and modCount=0;查找所有的String的length屬性的: select s.length from instanceof String s。
- 內(nèi)存分布及對象間依賴的眾多功能,均支持按字符串檢索、按正則檢索等操作。
- 按虛擬內(nèi)存地址尋址,根據(jù)對象的十六進(jìn)制地址查找對象。
此外,為了便于記憶與回顧,整理了如下腦圖:
2.2 常見內(nèi)存分析工具對比
下圖中 Y 表示支持,N 表示不支持,時(shí)間截至發(fā)稿前。
?注 1:Dump 文件包含快照被轉(zhuǎn)儲(chǔ)時(shí)刻的 Java 對象 在堆內(nèi)存中的分布情況,但快照只是瞬間的記錄,所以不包含對象在何時(shí)、在哪個(gè)方法中被分配這類信息。
注 2:一般堆外內(nèi)存溢出排查可結(jié)合 gperftools 與 btrace 排查,此類文章較多不展開介紹。
3. Quick Start 及使用技巧
3.1 Quick Start
注:Quick Start 文章較多,本文著重介紹安裝流程及使用技巧。
1、安裝 MAT:戳【下載鏈接】;也可直接集成到 Eclipse IDE中(路徑:Eclipse → Help → Eclipse Marketplace → 搜 “MAT”)。
2、調(diào)節(jié) MAT 堆內(nèi)存大小:MAT 分析時(shí)也作為 Java 進(jìn)程運(yùn)行,如果有足夠的內(nèi)存,建議至少分配 dump 文件大小*1.2 倍的內(nèi)存給 MAT,這樣分析速度會(huì)比較快。方式是修改MemoryAnalyer.ini文件,調(diào)整Xmx參數(shù)(Windows 可用搜索神器 everything 軟件查找并修改、MAC OS 一般在 /Applications/mat.app/Contents/Eclipse/MemoryAnalyzer.ini,如找不到可用 Alfred 軟件查詢修改)。
3、獲取堆快照 dump 文件(堆轉(zhuǎn)儲(chǔ)需要先執(zhí)行 Full GC,線上服務(wù)使用時(shí)請注意影響),一般用三種方式:
- 使用 JDK 提供的 jmap 工具,命令是 jmap -dump:format=b,file=文件名 進(jìn)程號(hào)。當(dāng)進(jìn)程接近僵死時(shí),可以添加 -F 參數(shù)強(qiáng)制轉(zhuǎn)儲(chǔ):jmap -F -dump:format=b,file=文件名 進(jìn)程號(hào)。
- 本地運(yùn)行的 Java 進(jìn)程,直接在 MAT 使用 File → accquire heap dump 功能獲取。
- 啟動(dòng) Java 進(jìn)程時(shí)配置JVM參數(shù):-XX:-HeapDumpOnOutOfMemoryError,當(dāng)發(fā)生 OOM 時(shí)無需人工干預(yù)會(huì)自動(dòng)生成 dump文件。指定目錄用 -XX:HeapDumpPath=文件路徑 來設(shè)置。
4、分析 dump 文件:路徑是 File → Open Heap Dump ,然后 MAT 會(huì)建立索引并分析,dump 文件較大時(shí)耗時(shí)會(huì)很長。分析后 dump 文件所在目錄會(huì)有后綴為 index 的索引文件,也會(huì)有包含 HTML 格式的后綴為 zip 的文件。
5、完成索引計(jì)算后,MAT 呈現(xiàn)概要視圖(Overview),包含三個(gè)部分:
- 全局概覽信息,堆內(nèi)存大小、類數(shù)量、實(shí)例數(shù)量、Class Loader數(shù)量。
- Unreachable Object Histogram,展現(xiàn)轉(zhuǎn)儲(chǔ)快照時(shí)可被回收的對象信息(一般不需要關(guān)注,除非 GC 頻繁影響實(shí)時(shí)性的場景分析才用到)
- Biggest Objects by Retained Size,展現(xiàn)經(jīng)過統(tǒng)計(jì)過的哪幾個(gè)實(shí)例所關(guān)聯(lián)的對象占內(nèi)存總和較高,以及具體占用的內(nèi)存大小,一般相關(guān)代碼比較簡單情況下,往往可以直接分析具體的引用關(guān)系異常,如內(nèi)存泄漏等。此外也包含了最大對象和鏈接支持繼續(xù)深入分析。 ?
6、如果代碼比較復(fù)雜,需要繼續(xù)使用 MAT 各種工具并結(jié)合業(yè)務(wù)代碼進(jìn)一步分析內(nèi)存異常的原因。最常用的幾項(xiàng)如下(具體案例、場景、使用方式在《JVM 內(nèi)存分析工具 MAT 的深度講解與實(shí)踐——進(jìn)階篇》詳細(xì)介紹):
- 查看堆整體情況的:Histogram、Dominator tree、Thread details等(各功能入口整理如下) ?
- MAT 分析過的 Top Consumers 、Leak Suspects等 ?
3.2 使用技巧及注意事項(xiàng)
1、注意對運(yùn)行進(jìn)程的性能影響:Heap dump 時(shí)會(huì)先進(jìn)行 Full GC,另外為保證對象數(shù)據(jù)視圖一致,需要在安全點(diǎn) Stop The World 暫停響應(yīng),線上服務(wù)進(jìn)行務(wù)必注意性能影響。可以采取以下技巧減少影響:
- 先禁用入口流量,再執(zhí)行 dump 動(dòng)作。
- 選擇影響較小時(shí) dump 內(nèi)存。
- 使用腳本捕獲指定事件時(shí) dump 內(nèi)存。
2、Dump 文件及建立的索引文件可能較大,如果開發(fā)機(jī)配置不足無法分析,可在服務(wù)器先執(zhí)行分析后,基于分析后的索引文件直接查看結(jié)果,另外也需要注意磁盤占用問題:
- 大文件分析方法:一般 dump 文件不高于分析機(jī)主存 1.2 倍可直接在開發(fā)機(jī)分析;若 dump 文件過大,可以使用 MAT 提供的腳本在配置高的高配機(jī)器先建立索引再直接展現(xiàn)索引分析結(jié)果(一般是 Linux 機(jī)器,可以使用 MAT 提供的腳本:./ParseHeapDump.sh $HEAPDUMP,堆信息有 unreachable 標(biāo)記的垃圾對象,在 dump 時(shí)也保存了下來,默認(rèn)不分析此部分?jǐn)?shù)據(jù),如需要在啟動(dòng)腳本 ParseHeapDump.sh 中加入:-keep_unreachable_objects)。
- 如果不關(guān)注堆中不可達(dá)對象,使用“l(fā)ive”參數(shù)可以減小文件大小,命令是 jmap -dump:live,format=b,file=
- Dump 前主動(dòng)手動(dòng)執(zhí)行一次 FULL GC ,去除無效對象進(jìn)一步減少 dump 堆轉(zhuǎn)儲(chǔ)及建立索引的時(shí)間。
- Dump文件巨大,建立索引后發(fā)現(xiàn)主視圖中對象占用內(nèi)存均較小,這是因?yàn)榻^大部分對象未被 GC Roots 引用可釋放。
- Dump 時(shí)注意指定到空間較大的磁盤位置,避免打滿分區(qū)影響服務(wù)。
- 建立 dump 索引機(jī)器的磁盤空間需要足夠大,一般至少是 dump 文件的兩倍,因?yàn)樯傻闹虚g索引文件也較大,如下圖: ?
3、其他
- JDK 版本問題:如遇“VMVersionMismatchException”,使用啟動(dòng)目標(biāo)進(jìn)程的 JDK 版本即可。
- 部分核心功能主界面未展現(xiàn),問題足夠復(fù)雜時(shí)需打開,如 MAT 默認(rèn)不打開 inspector,如需根據(jù)對象數(shù)據(jù)值做業(yè)務(wù)分析,建議打開該視圖。
- 配置了 HeapDumpOnOutOfMemoryError 參數(shù),但 OutOfMemoryError 時(shí)但沒有自動(dòng)生成 dump 文件,可能原因有三個(gè):應(yīng)用程序自行創(chuàng)建并拋出 OutOfMemoryError進(jìn)程的其他資源(如線程)已用盡C 代碼(如 JVM 源碼)中堆耗盡,這種可能由于不同的原因而出現(xiàn),例如在交換空間不足的情況下,進(jìn)程限制用盡或僅地址空間的限制,此時(shí) dump 文件分析并無實(shí)質(zhì)性幫助。
總結(jié)展望:至此本文講解了 MAT 實(shí)踐必備的初級內(nèi)容,在下一篇《JVM 內(nèi)存分析工具 MAT 的深度講解與實(shí)踐——進(jìn)階篇》會(huì)展開并詳細(xì)介紹 MAT 豐富的核心功能,每個(gè)功能點(diǎn)講解都會(huì)從具體場景聊起,幫助大家在實(shí)戰(zhàn)場景下加深體會(huì)實(shí)現(xiàn)進(jìn)階。
參考內(nèi)容
- MAT官網(wǎng):https://help.eclipse.org/2020-09/index.jsp?topic=/org.eclipse.mat.ui.help/welcome.html
作者|Q的博客|https://juejin.cn/post/6908665391136899079
JVM 內(nèi)存分析往往由團(tuán)隊(duì)較資深的同學(xué)來做,本系列通過3篇文章,深度解析并幫助讀者全面深度掌握 MAT 的使用方法。即使沒有 JVM 內(nèi)存分析的實(shí)踐經(jīng)驗(yàn),也能快速成為內(nèi)存分析高手!
本系列共三篇文章如下, 本文是第一篇入門篇:
- 《JVM 內(nèi)存分析工具 MAT 的深度講解與實(shí)踐——入門篇》 介紹 MAT 產(chǎn)品功能、基礎(chǔ)概念、與其他工具對比、Quick Start 指南。
- 《JVM 內(nèi)存分析工具 MAT 的深度講解與實(shí)踐——進(jìn)階篇》 展開并詳細(xì)介紹 MAT 的核心功能,并在具體實(shí)戰(zhàn)場景下講解幫大家加深體會(huì)。
- 《JVM 內(nèi)存分析工具 MAT 的深度講解與實(shí)踐——高階篇》 總結(jié)復(fù)雜內(nèi)存問題的系統(tǒng)性分析方法,并通過一個(gè)綜合案例提升大家的實(shí)戰(zhàn)能力。
總結(jié)
以上是生活随笔為你收集整理的envi 文件 生成mat_JVM 内存分析工具 MAT 的深度讲解与实践——入门篇的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: lisp 任意点 曲线距离_奇怪的知识增
- 下一篇: 二战德国为何钟爱坦克歼击车