您的位置:首頁>數碼>正文

MAT(Memory Analyzer Tool)使用心得

起因:最近在跟蹤產品的性能問題, 期間主要問題體現在JVM的記憶體回收問題, 使用MAT工具進行JVM記憶體分析(也可對android 的應用記憶體分析)

問題描述:

1、部分後端服務在運行一段時間後會突然年老代會變為100%

2、部分後端服務定期出現年輕代GC情況, 耗時超過2S

問題1解決步驟:

利用jmap指令(jmap -dump:format=b,file=檔案名 PID)生成記憶體快照檔。 檔案名支援相對路徑和絕對路徑, PID指Java應用的進程ID, 可通過JPS指令獲取, 在有些時候該指令無法直接生成記憶體快照, 需要額外補充-f, 原因會在稍後的文章中說明。

打開後, 直接選擇leak suspects選項(該選項表示MAT會自動幫我們分析記憶體洩漏最可能的類),

分析完後類比下圖(圖片來自網路)

一般來說, 該報告會告訴我們最可能洩露的類和相關實例, 我們點進打開後, 對Retained Heap最大的實例再點擊選擇outGoing references(當前物件, 引用的外部物件), 即可查看該實例中引用了哪些物件, 一直沒釋放,

從而導致該實例占了不少記憶體

根據步驟4基本就可以確認, 究竟是哪些物件實例強引用未能釋放, 從而導致記憶體持續上漲直至頻繁FGC, 這時候就可以拉上開發的童鞋根據代碼進行分析

回到問題的原點, 這次的問題發生的原因是:多例模式下, 大量的物件被載入到OSGI的核心容器中, 從而導致大併發情況下, 導致記憶體出現洩漏, 最後記憶體溢出

問題2解決步驟:

分析步驟與問題1並無偏差, 但奇怪的現象是生成的報告中任何物件的實例的大小都很小, 且總和與實際的記憶體檔相差甚遠

MAT預設是只分析reachable物件實例, 所以在"Preferences=>Memory Analyzer"中勾選"Keep Unreachable Objects", 刪除索引檔Dump同路徑下的所有".index", 即可看到所有的物件, 再根據上述步驟4進行分析

此時發現某個物件實例, 其某個屬性List無比龐大(size>10000)

後經與研發同事分析得知, 某些查詢動作會入庫, 從而導致日積月累的情況下, 查詢時就會創建一個額外的物件, 引發頻繁的young gc, 甚至full gc

問題反思:

版本測試時, 除了常規的功能測試外, 還要對核心業務進行性能測試, 根據時間進度可適當切割, 但不能缺失

場景測試時, 除了常規的場景測試外, 還需考慮當前的資料庫量級, 若當前表量級較大, 業務模組中的sql語句是否有做limit等限制

生產環境上應對應用做相關監控, 除了日常的伺服器本身性能監控外, 還需要對應用本身的各項指標監控, 例如:GC次數、GC耗時甚至young、s0、s1、pem、old等不同年代的監控。 根據日常的監控圖表來判斷當前服務是否正常

一般來說, young gc的次數要大於old gc和full gc, 且耗時是毫秒級。 不然, 則有可能:young年代設置過小, 應用創建了過大的物件, 存在大量強應用的物件實例等

參考資料:

https://my.oschina.net/flashsword/blog/265442

http://www.blogjava.net/rosen/archive/2010/06/13/323522.html

Next Article
喜欢就按个赞吧!!!
点击关闭提示