Java堆可以處于物理上不連續(xù)的內存空間上,只要邏輯上是連續(xù)的即可。Java堆就是各種對象分配和保存的內存空間,線程間共享。Java堆分為Eden區(qū),Survivor區(qū),tenured區(qū)和Permanent區(qū),如下圖所示。
Java堆的分配原則如下:
Perm Generation是JVM的駐留內存,用于存放JDK自身攜帶的CLASS,Interface的元數(shù)據(jù)等。被裝載進此區(qū)域的數(shù)據(jù)是不會被垃圾回收器GC回收掉的,關閉JVM時,釋放此區(qū)域所控制的內存。
Java對象的聲明周期在堆中從Young到Tenured,這個期間從Eden誕生到Tenured死亡。當EDEN區(qū)不夠用時,將觸發(fā)minor gc,GC會對EDEN區(qū)進行垃圾回收,將不再使用的對象進行銷毀,同時如果發(fā)現(xiàn)對象還被其他對象引用,則將對象移動到survivor區(qū),后面依此類推,當Tenured區(qū)發(fā)生GC時,稱為major gc,由于java中大部分對象的生命周期都很短,所以GC一般發(fā)生在Eden區(qū),因此minor gc發(fā)生的頻率比major gc要高很多。如果最后整個堆空間都滿了,則會爆出異常JVM對空間溢出:java.lang.OutOfMemoryError: java heap space。
即標記回收算法,將需要回收的對象標記,再統(tǒng)一回收。這種算法適合Perm代的對象,以為Perm代的存儲空間比較大,需要回收的又不多。
即復制算法,直接拷貝。適合Eden區(qū)的對象向survivor區(qū)拷貝,因為Eden區(qū)的對象大部分都需要GC,而且Eden區(qū)的容量小。
即標記整理算法,與標記清除算法不同,標記整理算法避免了內存碎片問題,它將所有存活的對象向內存的一端移動,“整理”完成后,一端是存活的對象一端是可回收內存,然后直接清除可回收內存。
最基本、最古老的收集器。這是一個單線程收集器,GC過程中,應用會被停掉,即stop-the-world。
實現(xiàn)代碼與serial差不多,不同的是這是一個多線程回收器。
Paralled scavenger收集器是一個新生代回收器,使用復制算法,也是一個多線程并行收集器。parallel scavenge收集器專注于提高吞吐量,吞吐量定義為:
吞吐量 = 用戶程序執(zhí)行時間/(用戶程序執(zhí)行時間 + 垃圾回收時間)
Serial old是Serial收集器的老年代版本。
Parallel Scavenge收集器的老年代版本。使用標記-整理算法。
主要需要熟悉的是總存儲空間大小,各個區(qū)的比例設置,針對不同的區(qū)設定不同的回收器和回收算法。在默認情況下有些選項是不打開的,因此需要手動配置,并且根據(jù)自己應用的情況選擇適當?shù)膮?shù)。
參數(shù) | 描述 |
–XX:+UseSerialGC | 使用串行GC收集器 |
–XX:+UseParallelGC | 使用并行GC收集器 |
–XX:+UseParallelOldGC | 使用parallel old收集器 |
–XX:+UseConcMarkSweepGC | 使用CMS收集器 |
-Xms | 初始狀態(tài)堆大小 |
-Xmx | 堆的最大大小 |
-XX:MaxPermSize=n | 設置Permanent區(qū)的大小 |
-XX:NewSize=n | 設置Young generation大小 |
-XX:NewRatio=n | 設置年輕代和年老代的比值 |
對于應用程序,在eclipse中可以通過工程屬性增加VM屬性,將GC輸出保存為日志文件。
GC輸出選項:
-XX:+PRintGC 輸出GC日志 -XX:+PrintGCDetails 輸出GC的詳細日志 -XX:+PrintGCTimeStamps 輸出GC的時間戳(以基準時間的形式) -XX:+PrintGCDateStamps 輸出GC的時間戳(以日期的形式,如 2013-05-04T21:53:59.234+0800) -XX:+PrintHeapAtGC 在進行GC的前后打印出堆的信息 -Xloggc:../logs/gc.log 日志文件的輸出路徑
日志輸出形式:
Java HotSpot(TM) Client VM (25.45-b02) for windows-x86 JRE (1.8.0_45-b14), built on Apr 10 2015 10:46:40 by "java_re" with MS VC++ 10.0 (VS2010)Memory: 4k page, physical 2074576k(402044k free), swap 4149152k(1441572k free)CommandLine flags: -XX:InitialHeapSize=16777216 -XX:MaxHeapSize=268435456 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintGCTimeStamps -XX:-UseLargePagesIndividualAllocation Heap def new generation total 4928K, used 885K [0x04600000, 0x04b50000, 0x09b50000) eden space 4416K, 20% used [0x04600000, 0x046dd5f0, 0x04a50000) from space 512K, 0% used [0x04a50000, 0x04a50000, 0x04ad0000) to space 512K, 0% used [0x04ad0000, 0x04ad0000, 0x04b50000) tenured generation total 10944K, used 0K [0x09b50000, 0x0a600000, 0x14600000) the space 10944K, 0% used [0x09b50000, 0x09b50000, 0x09b50200, 0x0a600000) Metaspace used 98K, capacity 2242K, committed 2368K, reserved 4480K
編寫了一個簡單的遞歸計算Fibbonaccy數(shù)列的程序,并在最后增加了一句System.gc()強制進行Full GC,得到的GC日志如下,回收后Eden區(qū)使用量為0。當服務器型的應用運行起來時,免不了會有多次GC,通過GC日志可以比較容易定位性能問題,比如full gc次數(shù)過多等。
{Heap before GC invocations=0 (full 0): def new generation total 4928K, used 1522K [0x04600000, 0x04b50000, 0x09b50000) eden space 4416K, 34% used [0x04600000, 0x0477c9e8, 0x04a50000) from space 512K, 0% used [0x04a50000, 0x04a50000, 0x04ad0000) to space 512K, 0% used [0x04ad0000, 0x04ad0000, 0x04b50000) tenured generation total 10944K, used 0K [0x09b50000, 0x0a600000, 0x14600000) the space 10944K, 0% used [0x09b50000, 0x09b50000, 0x09b50200, 0x0a600000) Metaspace used 259K, capacity 2280K, committed 2368K, reserved 4480K15.463: [Full GC (System.gc()) 15.477: [Tenured: 0K->776K(10944K), 0.0428098 secs] 1522K->776K(15872K), [Metaspace: 259K->259K(4480K)], 0.0688257 secs] [Times: user=0.02 sys=0.00, real=0.07 secs] Heap after GC invocations=1 (full 1): def new generation total 4992K, used 0K [0x04600000, 0x04b60000, 0x09b50000) eden space 4480K, 0% used [0x04600000, 0x04600000, 0x04a60000) from space 512K, 0% used [0x04a60000, 0x04a60000, 0x04ae0000) to space 512K, 0% used [0x04ae0000, 0x04ae0000, 0x04b60000) tenured generation total 10944K, used 776K [0x09b50000, 0x0a600000, 0x14600000) the space 10944K, 7% used [0x09b50000, 0x09c122f0, 0x09c12400, 0x0a600000) Metaspace used 259K, capacity 2280K, committed 2368K, reserved 4480K}Heap def new generation total 4992K, used 45K [0x04600000, 0x04b60000, 0x09b50000) eden space 4480K, 1% used [0x04600000, 0x0460b4a8, 0x04a60000) from space 512K, 0% used [0x04a60000, 0x04a60000, 0x04ae0000) to space 512K, 0% used [0x04ae0000, 0x04ae0000, 0x04b60000) tenured generation total 10944K, used 776K [0x09b50000, 0x0a600000, 0x14600000) the space 10944K, 7% used [0x09b50000, 0x09c122f0, 0x09c12400, 0x0a600000) Metaspace used 259K, capacity 2280K, committed 2368K, reserved 4480K
測試環(huán)境:
JVM: Java HotSpot(TM) Client VM (25.60-b23, mixed mode, sharing)
Java: version 1.8.0_60, vendor Oracle Corporation
Step1:
監(jiān)控界面,能夠直觀地看到JVM各個區(qū)域的內存使用情況。除了監(jiān)視虛擬機,還可以監(jiān)視應用的內存使用情況。嘗試對Eclipse的啟動進行優(yōu)化,可以很明顯的看到eclipse啟動時,S0的對象向S1拷貝,而old區(qū)的使用量略微增加。
還可以監(jiān)控當前CPU和內存負載情況,類加載數(shù)量和線程數(shù):
Step2:
eclipse安裝目錄下有個.ini文件,即eclipse的配置文件,將需要的參數(shù)配置填寫進去即可。啟動eclipse后,查看GC日志,發(fā)現(xiàn)整個啟動過程中共發(fā)生了27次GC,其中有3次Full GC,整個啟動過程,我掐指一算大概6~7秒,相當慢了。
通過參數(shù)-XX:NewSize=n 將Eden區(qū)重設為128m后,再次啟動eclipse發(fā)現(xiàn),這次就只發(fā)生了11次GC,下降了一般還多,啟動速度也明顯比原來快了一些。
Step3:
接著使用-Xverify:none禁掉類加載時的字節(jié)碼驗證過程,GC次數(shù)為10次,現(xiàn)在啟動速度基本為3秒多左右,比原來快了一倍。
{Heap before GC invocations=10 (full 4): def new generation total 36864K, used 35041K [0x04400000, 0x06bf0000, 0x0eea0000) eden space 32832K, 100% used [0x04400000, 0x06410000, 0x06410000) from space 4032K, 54% used [0x06410000, 0x06638570, 0x06800000) to space 4032K, 0% used [0x06800000, 0x06800000, 0x06bf0000) tenured generation total 57224K, used 40267K [0x0eea0000, 0x12682000, 0x24400000) the space 57224K, 70% used [0x0eea0000, 0x115f2ca0, 0x115f2e00, 0x12682000) Metaspace used 31836K, capacity 33329K, committed 33408K, reserved 34176K5.742: [GC (Allocation Failure) 5.742: [DefNew: 35041K->4031K(36864K), 0.0193873 secs] 75308K->46613K(94088K), 0.0194649 secs] [Times: user=0.02 sys=0.00, real=0.02 secs]
然而這種調優(yōu)粒度太粗,服務器上程序需要定位更精確的時間,所以需要更多參數(shù)來調試。
先寫到這里吧。
玄不救非,氪不改命。
1.http://timyang.net/java/java_gc_tunning/
2.ImportNew
新聞熱點
疑難解答