GC的階段
對每個對象而言,垃圾回收分為兩個階段:finalization和reclamation。
Java所使用的所有的GC算法都是通用GC算法概念的變種。
通用GC算法的假設:
Object Spaces(對象空間)
Young Spaces(年輕空間)
在java5和java6中有4中垃圾回收的算法,有一種算法將不再支持,剩余的三種垃圾回收算法是:serial,throughput and concurrent low pause。
GC發生的時刻受堆內存大小的影響。如果堆內存小,GC會執行的很快,但是又會很快的被填滿,因此GC比頻繁;如果堆內存很大,GC會執行的較慢,而且不會很快被填滿,因此執行的比較頻率比較低。
基本的GC調試
throughput goal -XX:GCTimeRatio=n: 表示花費總時間百分之多少的CPU時間去運行程序。
maximum pause time goal -XX:MaxGCPauseMillis=n:每次GC時程序暫停最多多少毫秒。
footprint goal:如果其他目標都達到了,那么首先減少heap size,直到前兩個goal不再滿足,然后再慢慢增加。直到滿足前面兩個goal。
-Xms=n (starting) and -Xmx=n (maximum) heap size,這兩個參數應該都很熟悉,就是JVM使用的最小堆內存數和最大堆內存數。
-XX:MinHeapFreeRatio=n, -XX:MaxHeapFreeRatio=n:最小和最大的空閑堆內存和被使用堆內存的比例。當空閑堆內存比例小於MinHeapFreeRatio時,內存空間開始擴展。當空閑堆內存比例大於MaxHeapFreeRatio時,內存空間開始減小。
-XX:NewSize=n, -XX:MaxNewSize=n:默認的young space的大小(包括eden + survivor 1 + survivor 2)。
-XX:NewRatio=n:young和tenured的比例。
-XX:SurvivorRatio=n:每個survivor space 和 eden之間的比例。
-XX:MaxPermSize=n:perm的最大size。
-XX:TargetSurvivorRatio=n:每次GC之后幸存下來的空間的目標比例。
-XX:+DisableExplicitGC:當此參數打開時,在程序中調用System.gc()將會不起作用。默認是off。
-XX:+ScavengeBeforeFullGC:當打開此參數時,在每次major collection時先執行一次minor collection。默認打開。
-XX:+UseGCOverheadLimit:當打開此參數時,如果總運行時間的98%的時間都在做GC,則拋出OutOfMemmoryError。默認打開。
參考資料:http://java.ociweb.com/mark/other-presentations/JavaGC.pdf
- finalization: 指運行這個對象的finalize的方法。
- reclamation: 回收被這個對象使用的內存。
- 首先確認對象是不可達的,即將被回收。
- 其次,如果對象有finalize方法,那么對象被添加進finalization queue中;然后在某個時間點finalize方法被調用以釋放finalize中的資源。
- 最后,回收對象占用的內存。
- finalize方法使得GC過程做了更多的事情,增加的GC的負擔。
- 如果某個對象的finalize方法運行時間過長,它會使得其他對象的finalize方法被延遲執行。
- finalize方法中如果創建了strong reference引用了其他對象,這會阻止此對象被GC。
- finalize方法有可能以不可確定的順序執行(也就是說要在安全性要求嚴格的場景中盡量避免使用finalize方法)。
- 不確保finalize方法會被及時調用,也許程序都退出了,但是finalize方法還沒被調用。
- Reference(or named Strong Reference)( 強引用):普通類型的引用。
- SoftReference( 軟引用):被這種引用指向的對象,如果此對象沒要再被其他Strong Reference引用的話,可能在任何時候被GC。雖然是可能在任何時候被GC,但是通常是在可用內存數比較低的時候,並且在程序拋出OutOfMemoryError之前才發生對此對象的GC。SoftReference通常被用作實現Cache的對象引用,如果這個對象被GC了,那么他可以在任何時候再重新被創建。另外,根據JDK文檔中介紹,實際JVM的實現是鼓勵不回收最近創建和最近使用的對象。SoftReference 類的一個典型用途就是用於內存敏感的高速緩存。
- WeakReference(弱引用):如果一個被WeakReference引用的對象,當沒要任何SoftReference和StrongReference引用時,立即會被GC。和SoftReference的區別是:WeakReference對象是被eagerly collected,即一旦沒要任何SoftReference和StrongReference引用,立即被清楚;而只被SoftReference引用的對象,不回立即被清楚,只有當內存不夠,即將發生OutOfMemoryError時才被清除,而且是先清除不常用的。SoftReference適合實現Cache用。WeakReference 類的一個典型用途就是規范化映射( canonicalized mapping )
- PhantomReference(虛引用):當沒有StrongReference,SoftReference和WeakReference引用時,隨時可被GC。通常和ReferenceQueue聯合使用,管理和清除與被引用對象(沒有finalize方法)相關的本地資源。
- Throughput(吞吐量):所有沒有花在執行GC上的時間占總運行時間的比重。
- Pauses(暫停):當GC在運行時程序的暫停次數。或者是在感興趣的暫停次數中,暫停的平均時長和最大時長。
- Footprint(足跡?):當前使用的堆內存大小。
- Promptness(及時性):不再使用的對象多久能被清除掉並釋放其內存。
Java所使用的所有的GC算法都是通用GC算法概念的變種。
通用GC算法的假設:
- 最近創建的對象很可能很快就不可達了(unreachable,即可被回收了),比如方法內部聲明的本地變量,當程序運行出了本地變量的作用范圍后,本地變量引用的對象就很快不可達了。
- 一個對象保持可達(reachable)的越久就越不可能被回收。
Object Spaces(對象空間)
- Young:年輕代中保存着剛創建的對象,這個代中的對象能夠“minor” or “major” 收集中被回收。
- Tenured:年老代中保存着從年輕代中幸存下來的對象,只能夠在“major”中被回收。
- Perm:永久代中保存着JVM所需的對象,比如Class對象和Method對象,以及他們的字節碼和內部字符串等。對Perm中的對象GC意味着所有的Class都被卸載了。

Young Spaces(年輕空間)
- Eden space:存儲自從上次GC完畢之后新創建的對象,除了屬於Perm的對象。當minor collection發生時,Eden space中的對象或者GC清理掉,或者被移到survivor space。
- Survivor spaces:這個空間中存儲的是自從上次GC幸存下來的young object。在minor GC中,這些對象或者被GC清理掉,或者被移到另外一個survivor空間中。
- Minor collection當young space被占滿時執行。它比major collections快,因為minor collection僅僅檢查major collection相應的一個子集對象。minor collection比major collection發生的頻率高。
- Major collection當tenured space被占滿時執行。他會清理tenured和young。
在java5和java6中有4中垃圾回收的算法,有一種算法將不再支持,剩余的三種垃圾回收算法是:serial,throughput and concurrent low pause。
- Stop the world(停止所有程序的方式):在這種方式運行的GC,在GC完成前,JVM中的所有程序都不允許運行。Serial collector此時做minor和major收集。Throughput collector此時做major collector。
- Incremental(增量運行方式):目前沒要Java GC算法支持這種運行方式。GC以這種方式運行時,GC允許程序做一小段時間的工作,然后做垃圾回收工作。
- Concurrent(並行運行):Throughput collector此時做minor collect,Concurrent low pause collector此時做minor和major收集。在這種運行方式下,GC和程序並行的運行,因此程序僅僅被短暫的暫停。
- Serial算法: 使用-XX:+UseSerialGC開啟此算法的GC。GC使用和應用程序相同的線程去做minor collection和major collection。
- Throughput:使用-XX:+UseParallelGC開啟此算法GC。GC使用多線程去做minor collection以減少程序停止的時間。但是對於major collection,還是使用同程序相同的線程去做。當具有多核cpu時,並且程序有大量的短生命周期的對象時,並且對程序停頓時間不限制時較好。
- Concurrent Low Pause: 使用-XX:+UseConcMarkSweepGC開啟此算法GC。使用多線程去做minor和major collection。當具有多核cpu,並且程序有大量的長生命周期的對象,並且對程序停頓時間有限制時,效果較好。
GC發生的時刻受堆內存大小的影響。如果堆內存小,GC會執行的很快,但是又會很快的被填滿,因此GC比頻繁;如果堆內存很大,GC會執行的較慢,而且不會很快被填滿,因此執行的比較頻率比較低。
基本的GC調試
throughput goal -XX:GCTimeRatio=n: 表示花費總時間百分之多少的CPU時間去運行程序。
maximum pause time goal -XX:MaxGCPauseMillis=n:每次GC時程序暫停最多多少毫秒。
footprint goal:如果其他目標都達到了,那么首先減少heap size,直到前兩個goal不再滿足,然后再慢慢增加。直到滿足前面兩個goal。
-Xms=n (starting) and -Xmx=n (maximum) heap size,這兩個參數應該都很熟悉,就是JVM使用的最小堆內存數和最大堆內存數。
-XX:MinHeapFreeRatio=n, -XX:MaxHeapFreeRatio=n:最小和最大的空閑堆內存和被使用堆內存的比例。當空閑堆內存比例小於MinHeapFreeRatio時,內存空間開始擴展。當空閑堆內存比例大於MaxHeapFreeRatio時,內存空間開始減小。
-XX:NewSize=n, -XX:MaxNewSize=n:默認的young space的大小(包括eden + survivor 1 + survivor 2)。
-XX:NewRatio=n:young和tenured的比例。
-XX:SurvivorRatio=n:每個survivor space 和 eden之間的比例。
-XX:MaxPermSize=n:perm的最大size。
-XX:TargetSurvivorRatio=n:每次GC之后幸存下來的空間的目標比例。
-XX:+DisableExplicitGC:當此參數打開時,在程序中調用System.gc()將會不起作用。默認是off。
-XX:+ScavengeBeforeFullGC:當打開此參數時,在每次major collection時先執行一次minor collection。默認打開。
-XX:+UseGCOverheadLimit:當打開此參數時,如果總運行時間的98%的時間都在做GC,則拋出OutOfMemmoryError。默認打開。
參考資料:http://java.ociweb.com/mark/other-presentations/JavaGC.pdf