Memory Analyzer Tool 使用


       轉載出處:https://wensong.iteye.com/blog/1986449

       最近一段時間一直在研究熱部署,熱部署中涉及到一個比較頭痛的問題就是查內存泄露(Memory Leak),於是乎在研究熱部署的過程中,干的最多的一件事就是查內存泄露。
       查內存泄露,最開始嘗試用JDK自身的工具去解決這件事,通過jstat和jmap,去發現是否有內存泄露,當判斷有內存泄露存在時,試圖要去尋找內存泄露的點時,發現單純使用JDK自身提供的工具沒有什么很好的辦法,我嘗試過Jhat,發現查起來太困難了,后來對比網上推薦的工具,我選擇了MAT(Memory Analyzer Tool)。
       MAT是一個eclipse的插件,上手起來比較快。它能夠快速的分析dump文件,可以直觀的看到各個對象在內存占用的量大小,以及類實例的數量,對象之間的引用關系,找出對象的GC Roots相關的信息,此外還能生成內存泄露報表,疑似泄露大對象的報表等等。

  • 安裝MAT
  • 可以選擇eclipse插件的方式安裝
    • http://download.eclipse.org/mat/1.3/update-site/
  • 也可以選擇單獨MAT程序下載安裝
    • http://www.eclipse.org/mat/downloads.php
  • 使用MAT查內存溢出
    • 生成dump
  • 生成dump文件,可以直接用 jmap -dump:format=b,file=xxx.bin ${pid}的方式
  • 也可以直接用MAT生成,File-》Acquire Heap Dump -》選擇要dump的java進程-》finish就可以了
  • 生成完dump后,可以用MAT打開 dump(如果是MAT dump完后會自動進行解析),File-》Open Heap Dump 對dump文件進行解析,最終生成一個Overview視圖,這個圖是一個概要圖,顯示了一些統計信息,包括整個size大小,class數量,以及對象 的數量,同時還將生成一個大對象的top圖,並線顯示大對象占用內存的百分比。
    • 類似:size:2.2MB Classes:3.3k Objects:50.1k ClassLoader:84 Unreachable Objects Histogram
    • 找出溢出源
      • Histogram視圖(截圖里柱子那個,邊上的是Dominator Tree ):列出每個class產生了多少個實例,以及占有多大內存,所占百分比
        • 可以很容易找出站內存最多的幾個類,根據Retained Heap排序,找出前幾個。
        • 可以分不同的維度來查看類的Histogram視圖,Group by class、Group by superclass、Group by class  loader、Group by package
        • 只要有溢出,時間久了,溢出類的實例數量或者其占有的內存會越來越多,排名也就越來越前,通過多次對比不同時間點下的Histogram圖對比就能很容易把溢出類找出來。


        •  
        • Dominator Tree(支配樹):列出每個對象(Object instance)與其引用關系的樹狀結構,還包含了占有多大內存,所占百分比
  • 可以很容易的找出占用內存最多的幾個對象,根據Percentage(百分比)來排序。
  • 可以分不同維度來查看對象的Dominator Tree視圖,Group by class、Group by class  loader、Group by package
  • 和Histogram類似,時間久了,通過多次對比也可以把溢出對象找出來,Dominator Tree和Histogram的區別是站的角度不一樣,Histogram是站在類的角度上去看,Dominator Tree是站的對象實例的角度上看,Dominator Tree可以更方便的看出其引用關系。


  •  
    • 定位溢出的原因
      • 通過Path to GC Roots或者Merge Shortest Paths to GC Roots


      •  
  • 通 過Histogram視圖或者Dominator Tree視圖,找到疑似溢出的對象或者類后,選擇Path to GC Roots或者Merge Shortest Paths to GC Roots,這里有很多過濾選項,一般來講可以選擇exclude all plantom/weak/soft etc. references。這樣就排除了虛引用、弱引用、以及軟引用,剩下的就是強引用。從GC上說,除了強引用外,其他的引用在JVM需要的情況下是都可以 被GC掉的,如果一個對象始終無法被GC,就是因為強引用的存在,從而導致在GC的過程中一直得不到回收,因此就內存溢出了。
  • 接下來就需要直接定位具體的代碼,看看如何釋放這些不該存在的對象,比如是否被cache住了,還是其他什么原因。
  • 找到原因,清理干凈后,再對照之前的操作,看看對象是否還再持續增長,如果不在,那就說明這個溢出點被成功的堵住了。
  • 最后用jstat跟蹤一段時間,看看Old和Perm區的內存是否最終穩定在一個范圍內,如果長時間穩定在一個范圍,那溢出的問題就解決了,如果還再繼續增長,那繼續用上述方法,看看是否存在其他代碼的溢出點,繼續找出,將其堵住。


  •  

     
  • 此外通過list objects或show objects by class也可以達到類似的效果,不過沒看GC Roots的方式直觀,這里就不細說了。
  • list objects -- with outgoing references : 查看這個對象持有的外部對象引用。
  • list objects -- with incoming references : 查看這個對象被哪些外部對象引用。
  • show objects by class  --  with outgoing references :查看這個對象類型持有的外部對象引用
  • show objects by class  --  with incoming references :查看這個對象類型被哪些外部對象引用  


免責聲明!

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



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