1.怎么查看日志
- 首先在eclipse中準(zhǔn)備一個
Gcdemo.java
package leetcode;
public class Gcdemo {
public static void main(String[] args) {
int _1m = 1024 * 1024;
byte[] data = new byte[_1m];
// 將data置為null即讓它成為垃圾
data = null;
// 通知垃圾回收器回收垃圾
System.gc();
}
}
- 按如下圖運行這個demo
右鍵-Run AS-Run Configurations
- 輸入如下圖參數(shù)
-XX:+PrintGCDetails
- 得到如圖內(nèi)容
當(dāng)然也可以通過cmd的形式。
在工程的bin層打開cmd 輸入命令:java -XX:+PrintGCDetails leetcode.Gcdemo
2.GC日志的參數(shù)
首先了解關(guān)于輸出GC日志的參數(shù)有以下幾種
-XX:+PrintGC 輸出GC日志
-XX:+PrintGCDetails 輸出GC的詳細(xì)日志
-XX:+PrintGCTimeStamps 輸出GC的時間戳(以基準(zhǔn)時間的形式)
-XX:+PrintGCDateStamps 輸出GC的時間戳(以日期的形式,如 2013-05-04T21:53:59.234+0800)
-XX:+PrintHeapAtGC 在進(jìn)行GC的前后打印出堆的信息
-Xloggc:../logs/gc.log 日志文件的輸出路徑
3.分析日志
[GC (System.gc()) [PSYoungGen: 2908K->680K(54784K)] 2908K->688K(180736K), 0.0314018 secs] [Times: user=0.00 sys=0.00, real=0.07 secs]
[Full GC (System.gc()) [PSYoungGen: 680K->0K(54784K)] [ParOldGen: 8K->530K(125952K)] 688K->530K(180736K), [Metaspace: 2656K->2656K(1056768K)], 0.0115257 secs] [Times: user=0.03 sys=0.00, real=0.01 secs]
Heap
PSYoungGen total 54784K, used 471K [0x0000000782f00000, 0x0000000786c00000, 0x00000007c0000000)
eden space 47104K, 1% used [0x0000000782f00000,0x0000000782f75da0,0x0000000785d00000)
from space 7680K, 0% used [0x0000000785d00000,0x0000000785d00000,0x0000000786480000)
to space 7680K, 0% used [0x0000000786480000,0x0000000786480000,0x0000000786c00000)
ParOldGen total 125952K, used 530K [0x0000000708c00000, 0x0000000710700000, 0x0000000782f00000)
object space 125952K, 0% used [0x0000000708c00000,0x0000000708c84848,0x0000000710700000)
Metaspace used 2663K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 288K, capacity 386K, committed 512K, reserved 1048576K
①GC日志開頭的[GC和[Full GC說明了這次垃圾收集的類型.
Partial GC(局部 GC): 并不收集整個 GC 堆的模式
- Young GC: 只收集young gen的GC,Young GC還有種說法就叫做 "Minor GC"
- Old GC: 只收集old gen的GC。只有垃圾收集器CMS的concurrent collection 是這個模式
- Mixed GC: 收集整個young gen 以及部分old gen的GC。只有垃圾收集器 G1有這個模式
Full GC 就是收集整個堆,包括新生代,老年代,永久代(在JDK 1.8及以后,永久代會被移除,換為metaspace(元空間))等收集所有部分的模式。
針對不同的垃圾收集器,F(xiàn)ull GC的觸發(fā)條件可能不都一樣。按HotSpot VM的serial GC的實現(xiàn)來看,觸發(fā)條件是:
1.當(dāng)準(zhǔn)備要觸發(fā)一次 young GC時,如果發(fā)現(xiàn)統(tǒng)計數(shù)據(jù)說之前 young GC的平均晉升大小比目前的 old gen剩余的空間大,則不會觸發(fā)young GC而是轉(zhuǎn)為觸發(fā) full GC
(因為HotSpot VM的GC里,除了垃圾回收器 CMS的concurrent collection 之外,其他能收集old gen的GC都會同時收集整個GC堆,包括young gen,所以不需要事先準(zhǔn)備一次單獨的young GC)
2.如果有永久代(perm gen),要在永久代分配空間但已經(jīng)沒有足夠空間時,也要觸發(fā)一次 full GC
3.執(zhí)行System.gc(),heap dump帶GC,其默認(rèn)都是觸發(fā) full GC.
②[PSYoungGen和[ParOldGen是指GC發(fā)生的區(qū)域,分別代表使用Parallel Scavenge垃圾收集器的新生代和使用Parallel old垃圾收集器的老生代。為什么是這兩個垃圾收集器組合呢?因為我的jvm開啟的模式是Server,而Server模式的默認(rèn)垃圾收集器組合便是這個,在命令行輸入java -version就可以看到自己的jvm默認(rèn)開啟模式。還有一種是client模式,默認(rèn)組合是Serial收集器和Serial Old收集器組合。

③在方括號中
PSYoungGen:后面的2908K->680K(54784K)代表的是GC前該內(nèi)存區(qū)域已使用的容量->GC后該內(nèi)存區(qū)域已使用的容量(該內(nèi)存區(qū)域總?cè)萘?/strong>)④在方括號之外的
2908K->688K(180736K)代表的是GC前Java堆已使用容量->GC后Java堆已使用容量(Java堆總?cè)萘?/strong>)⑤再往后的
0.0314018 secs代表該內(nèi)存區(qū)域GC所占用的時間,單位是秒。⑥再后面的
[Times: user=0.00 sys=0.00, real=0.07 secs],user代表進(jìn)程在用戶態(tài)消耗的CPU時間,sys代表代表進(jìn)程在內(nèi)核態(tài)消耗的CPU時間、real代表程序從開始到結(jié)束所用的時鐘時間。這個時間包括其他進(jìn)程使用的時間片和進(jìn)程阻塞的時間(比如等待 I/O 完成)
下面是堆詳細(xì)信息的日志
Heap
PSYoungGen total 54784K, used 471K [0x0000000782f00000, 0x0000000786c00000, 0x00000007c0000000)
eden space 47104K, 1% used [0x0000000782f00000,0x0000000782f75da0,0x0000000785d00000)
from space 7680K, 0% used [0x0000000785d00000,0x0000000785d00000,0x0000000786480000)
to space 7680K, 0% used [0x0000000786480000,0x0000000786480000,0x0000000786c00000)
ParOldGen total 125952K, used 530K [0x0000000708c00000, 0x0000000710700000, 0x0000000782f00000)
object space 125952K, 0% used [0x0000000708c00000,0x0000000708c84848,0x0000000710700000)
Metaspace used 2663K, capacity 4486K, committed 4864K, reserved 1056768K
class space used 288K, capacity 386K, committed 512K, reserved 1048576K
先了解下Java memory劃分:
Java memory主要分heap memory和non-heap memory,如下圖:

⑦第一行為新生代的大小,大小為
54784K。而新生代又分為三個區(qū)域分別叫Eden,和倆個Survivor spaces(from和to)。Eden用來存放新的對象,Survivor spaces用于 新對象 升級到Tenured area時的 拷貝。默認(rèn)的,Edem : from : to = 8 : 1 : 1( 可以通過參數(shù)–XX:SurvivorRatio來設(shè)定 ),即:Eden = 8/10 的新生代空間大小,from = to = 1/10的新生代空間大小。
⑧默認(rèn)的,新生代 ( Young) 與老年代 ( Old ) 的比例的值為 1:2( 該值可以通過參數(shù)–XX:NewRatio來指定 ),即:新生代 ( Young) = 1/3的堆空間大小。老年代 ( Old) = 2/3 的堆空間大小。其中,新生代 ( Young) 被細(xì)分為 Eden 和 兩個 Survivor區(qū)域,這兩個 Survivor區(qū)域分別被命名為 from 和 to,以示區(qū)分。
⑨ParOldGen為老年代,大小為125952K,大約為PSYoungGen內(nèi)存大小的2倍。 從JDK8開始,永久代(PermGen)的概念被廢棄掉了,取而代之的是一個稱為Metaspace(元空間)的存儲空間。Metaspace與PermGen之間最大的區(qū)別在于:Metaspace并不在虛擬機中,而是使用本地內(nèi)存。



