一 、問題定位java
手段一:經過 jstat -gcutil 快速定位GC問題(首先)瀏覽器
命令格式: jstat -gcutil <pid> <period> 網絡
命令樣例:jstat -gcutil 11900 3sapp
------> 監控進程11900的GC狀況, 每3s輸出一條記錄。工具
要點:O列(老年代內存使用率)一直接近100%;spa
FG列(Full GC次數) 一直增加。對象
手段二:增長Xmx參數,加大堆內存排除堆內存太小因素影響。進程
在jstat -gcutil 的O列佔滿狀況,需進一步排除是不是堆內存分配太小,知足不了業務請求量致使。ip
查看最大堆內存命令:jinfo -flag MaxHeapSize <pid> 。內存
假如開始是4G,修改爲8G:java -Xmx8G
要點:增長最大堆內存後,使用jstat -gcutil 看O列是否滿負,若是仍是滿負, 則可基本肯定是內存泄露。
手段三:使用 jmap -histo 命令定位內存泄露具體對象。
該命令展現全部類的實例個數以及內存用量狀況,並按照使用量降序輸出,通常本身寫的類有內存泄露,那會名列前茅。
命令1:jmap -histo <pid>
命令樣例:jmap -histo 42530 | head -n 20
輸出對應進程當前全部存活對象的堆內存佔用狀況,找到"突出" 的嫌疑類。
命令2:jmap -histo:live <pid>
帶上live,會觸發一次Full GC後再輸出結果,實際上就是回收了無用的對象,輸出真正存活的對象狀況。若是嫌疑類名實例數不減,那麼十有八九這個類就是致使內存泄露根因。
要點:兩個命令對比觀察Full GC後,實例數不減的類,重點關注排在前面的幾個本身寫的類名。
手段四:使用 jmap -dump:file 導出堆內存數據。
經過手段三,通常能夠定位出代碼位置,但代碼中不少地方引用了這個類,則要導出 Dump 文件,進一步分析泄露對象的GCRoot 。
命令:jmap -dump:file=<文件名> <pid>
樣例:jmap -dump:file=app.dump 9336
分析dump文件的工具:除了JDK自帶的 jhat , jvisualvm ,還有第三方的MAT,jprofiler等。
內存泄露的話,dump文件也會很大,爲了防止卡死,通常會將Xmx控制在一個合適的大小(2G) ,重現問題後, 再導出dump 。
要點:將Xmx設小一點,再導出dump。
手段五:jhat分析dump文件,尋找GC Root。
由於網絡拷貝大容量的dump文件諸多不便,因此須要現網直接分析dump文件,jhat能夠啓動一個http服務,提供頁面遠程分析對象引用狀況。
命令:jhat -J-Xmx2G -port <port> <dump文件>
樣例:jhat -J-Xmx2G app.dump
其中Xmx2G表明使用2G堆內存運行jhat,下一步可瀏覽器分析了,URL:http://ip:7000
要點:首先連接到嫌疑類的具體某個對象頁面,分析這個對象的引用狀況是否正常,再經過「Reference chains from Rootset 」獲取全部的GC Root ,進而定位到具體代碼位置。