MAT(Memory Analyzer Tool)使用心得


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

 

問題描述

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

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

 

問題1解決步驟

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

  2. 在官網下載MAT獨立包(推薦64位,並修改MemoryAnalyzer.ini文件中的-Xmx,確保其值大於你的內存快照文件大小,否則MAT打開內存文件會報內存溢出),打開之前保存的內存快照文件

  3. 打開后,直接選擇leak suspects選項(該選項表示MAT會自動幫我們分析內存泄漏最可能的類),分析完后類比下圖(圖片來自網絡)

  4. 一般來說,該報告會告訴我們最可能泄露的類和相關實例,我們點進打開后,對Retained Heap最大的實例再點擊選擇outGoing references(當前對象,引用的外部對象),即可查看該實例中引用了哪些對象,一直沒釋放,從而導致該實例占了不少內存

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

  6. 回到問題的原點,這次的問題發生的原因是:多例模式下,大量的對象被加載到OSGI的核心容器中,從而導致大並發情況下,導致內存出現泄漏,最后內存溢出

 

問題2解決步驟

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

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

  3. 此時發現某個對象實例,其某個屬性List無比龐大(size>10000)

  4. 后經與研發同事分析得知,某些查詢動作會入庫,從而導致日積月累的情況下,查詢時就會創建一個額外的對象,引發頻繁的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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM