1、分析GC日誌java
/** * @author : Hejinsheng * @date : 2019/1/18 0018 * @Description: 模擬FULL GC/YOUNG GC * -Xms100M -Xmx100M -Xmn32m -XX:SurvivorRatio=8 -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError */ public class GCTest { public static void main(String[] args) { List<Object> list = new ArrayList<>(); for(int i=0;;i++){ System.out.println(i); list.add(new byte[1024]); } } }
打印的GC信息linux
[Full GC (Ergonomics) [PSYoungGen: 26624K->26623K(29696K)] [ParOldGen: 69631K->69630K(69632K)] 96255K->96253K(99328K), [Metaspace: 3298K->3298K(1056768K)], 0.0200149 secs] [Times: user=0.03 sys=0.00, real=0.02 secs]
[Full GC (Ergonomics) [PSYoungGen: 26624K->26623K(29696K)] [ParOldGen: 69631K->69631K(69632K)] 96255K->96255K(99328K), [Metaspace: 3298K->3298K(1056768K)], 0.0177546 secs] [Times: user=0.08 sys=0.00, real=0.02 secs]
[Full GC (Allocation Failure) [PSYoungGen: 26623K->26623K(29696K)] [ParOldGen: 69631K->69613K(69632K)] 96255K->96236K(99328K), [Metaspace: 3298K->3298K(1056768K)], 0.0466197 secs] [Times: user=0.03 sys=0.00, real=0.05 secs]多線程
1. 最前面的數字217.539:表明GC發生的時間,從虛擬機啓動開始算起工具
2. GC日誌開頭的[GC和FULL GC]說明此次垃圾收集的停頓類型,而不是區分新生代和老年代的。spa
FULL GC : 說明此次GC是發生了線程停頓Stop-The-World,若是是System.gc()方法所觸發的收集,,那麼在這裏將顯示[Full GC (System)線程
3. [DefNew,[Tenured,[Perm表示GC發生的區域,這裏顯示的區域名稱和使用的垃圾收集器是密切相關的日誌
1>在Serial收集器中新生代名爲Default New Generation ,顯示就是DefNeworm
2>垃圾收集器ParNew中新生代名稱就會變爲[Parnew,意思爲Parallel New Generation 對象
3>若是採用Parrallel Scavenge收集器,那麼它配套的新生代名稱爲PSYongGenblog
老年代和永久代同理,名稱由垃圾收集器決定
4.[DefNew: 102646K->10770K(102976K), 0.0415902 secs] 239776K->153169K(331528K), 0.0416785 secs] [Times: user=0.03 sys=0.02, real=0.04 secs] 就這段而言,
1>方括號內部102646K->10770K(102976K)的含義是GC前改內存區域已使用內存->GC後改內存區域使用容量(該內存區域總容量)
2>方括號外 239776K->153169K(331528K)表示GC前java堆已使用容量->GC後java堆已使用容量(java堆總容量)
3>在日後時間表示該內存區域gc清理用的時間
4>[Times: user=0.03 sys=0.02, real=0.04 secs]
這裏面的user、sys和real與linux的time命令所輸出的時間含義一致,分別表示用戶態消耗的CPU時間、內核態消耗的CPU事件和操做從開始到結束經歷的牆鍾時間
牆鍾時間和CPU時間的區別是,牆鍾時間包括各類非運算的等待耗時(i/o,線程阻塞),而CPU時間不包括這些,可是若是是多核,
多線程會疊加這些CPU時間,此時user或sys時間超過real時間徹底是正常的
2、獲取堆轉儲的幾種方式
Heap Dump 是 Java進程所使用的內存狀況在某一時間的一次快照。以文件的形式持久化到磁盤中。
Heap Dump的格式有不少種,並且不一樣的格式包含的信息也可能不同。但總的來講,Heap Dump通常都包含了一個堆中的Java Objects, Class等基本信息。同時,當你在執行一個轉儲操做時,每每會觸發一次GC,因此你轉儲獲得的文件裏包含的信息一般是有效的內容(包含比較少,或沒有垃圾對象了) 。
Heap Dump 包含的信息
全部的對象信息
對象的類信息、字段信息、原生值(int, long等)及引用值
全部的類信息
類加載器、類名、超類及靜態字段
垃圾回收的根對象
根對象是指那些能夠直接被虛擬機觸及的對象
線程棧及局部變量
包含了轉儲時刻的線程調用棧信息和棧幀中的局部變量信息
Heap Dump 獲取方式
1. 使用 jmap 命令生成 dump 文件
jmap -dump:live,format=b,file=d:\dump\heap.hprof <pid>
2. 使用 jcmd 命令生成 dump 文件
jcmd <pid> GC.heap_dump d:\dump\heap.hprof
3. 使用 JVM 參數獲取 dump 文件
1. -XX:+HeapDumpOnOutOfMemoryError
當OutOfMemoryError發生時自動生成 Heap Dump 文件。
這但是一個很是有用的參數,由於當你須要分析Java內存使用狀況時,每每是在OOM(OutOfMemoryError)發生時。
2. -XX:+HeapDumpBeforeFullGC
當 JVM 執行 FullGC 前執行 dump。
3. -XX:+HeapDumpAfterFullGC
當 JVM 執行 FullGC 後執行 dump。
4. -XX:+HeapDumpOnCtrlBreak
交互式獲取dump。在控制檯按下快捷鍵Ctrl + Break時,JVM就會轉存一下堆快照。
5. -XX:HeapDumpPath=d:\test.hprof
指定 dump 文件存儲路徑。
注意:JVM 生成 Heap Dump 的時候,虛擬機是暫停一切服務的。若是是線上系統執行 Heap Dump 時須要注意。
分析 工具:jdk 自帶的工具 jvisualvm、Eclipse memory analyzer(jmat)、JProfiler 等。
3、jvisualvm使用
一、點擊文件-裝入,載入dump下來的文件
二、點擊類選項卡
三、根據上圖分析實例數或佔用大小比例較高的類,右鍵 「在實例視圖中顯示」,如
找到可能發生內存泄漏或內存溢出的根對象