除直接調用System.gc外,觸發Full GC執行的狀況有以下四種。java
1. 舊生代空間不足算法
舊生代空間只有在新生代對象轉入及建立爲大對象、大數組時纔會出現不足的現象,當執行Full GC後空間仍然不足,則拋出以下錯誤:數組
java.lang.OutOfMemoryError: Java heap space 併發
爲避免以上兩種情況引發的Full GC,調優時應儘可能作到讓對象在Minor GC階段被回收、讓對象在新生代多存活一段時間及不要建立過大的對象及數組。spa
2. Permanent Generation空間滿日誌
Permanent Generation中存放的爲一些class的信息等,當系統中要加載的類、反射的類和調用的方法較多時,Permanent Generation可能會被佔滿,在未配置爲採用CMS GC的狀況下會執行Full GC。若是通過Full GC仍然回收不了,那麼JVM會拋出以下錯誤信息:對象
java.lang.OutOfMemoryError: PermGen space 內存
爲避免Perm Gen佔滿形成Full GC現象,可採用的方法爲增大Perm Gen空間或轉爲使用CMS GC。ci
3. CMS GC時出現promotion failed和concurrent mode failurerem
對於採用CMS進行舊生代GC的程序而言,尤爲要注意GC日誌中是否有promotion failed和concurrent mode failure兩種情況,當這兩種情況出現時可能會觸發Full GC。
promotion failed是在進行Minor GC時,survivor space放不下、對象只能放入舊生代,而此時舊生代也放不下形成的;concurrent mode failure是在執行CMS GC的過程當中同時有對象要放入舊生代,而此時舊生代空間不足形成的。
應對措施爲:增大survivor space、舊生代空間或調低觸發併發GC的比率,但在JDK 5.0+、6.0+的版本中有可能會因爲JDK的bug29致使CMS在remark完畢後好久才觸發sweeping動做。對於這種情況,可經過設置-XX: CMSMaxAbortablePrecleanTime=5(單位爲ms)來避免。
4. 統計獲得的Minor GC晉升到舊生代的平均大小大於舊生代的剩餘空間
這是一個較爲複雜的觸發狀況,Hotspot爲了不因爲新生代對象晉升到舊生代致使舊生代空間不足的現象,在進行Minor GC時,作了一個判斷,若是以前統計所獲得的Minor GC晉升到舊生代的平均大小大於舊生代的剩餘空間,那麼就直接觸發Full GC。
例如程序第一次觸發Minor GC後,有6MB的對象晉升到舊生代,那麼當下一次Minor GC發生時,首先檢查舊生代的剩餘空間是否大於6MB,若是小於6MB,則執行Full GC。
當新生代採用PS GC時,方式稍有不一樣,PS GC是在Minor GC後也會檢查,例如上面的例子中第一次Minor GC後,PS GC會檢查此時舊生代的剩餘空間是否大於6MB,如小於,則觸發對舊生代的回收。
除了以上4種情況外,對於使用RMI來進行RPC或管理的Sun JDK應用而言,默認狀況下會一小時執行一次Full GC。可經過在啓動時經過- java -Dsun.rmi.dgc.client.gcInterval=3600000來設置Full GC執行的間隔時間或經過-XX:+ DisableExplicitGC來禁止RMI調用System.gc。
*對象分配規則
1.對象優先分配在Eden區,若是Eden區沒有足夠的空間時,虛擬機執行一次Minor GC。
2.大對象直接進入老年代(大對象是指須要大量連續內存空間的對象)。這樣作的目的是避免在Eden區和兩個Survivor區之間發生大量的內存拷貝(新生代採用複製算法收集內存)。
3.長期存活的對象進入老年代。虛擬機爲每一個對象定義了一個年齡計數器,若是對象通過了1次Minor GC那麼對象會進入Survivor區,以後每通過一次Minor GC那麼對象的年齡加1,直到達到閥值對象進入老年區。
4.動態判斷對象的年齡。若是Survivor區中相同年齡的全部對象大小的總和大於Survivor空間的一半,年齡大於或等於該年齡的對象能夠直接進入老年代。
5.空間分配擔保。每次進行Minor GC時,JVM會計算Survivor區移至老年區的對象的平均大小,若是這個值大於老年區的剩餘值大小則進行一次Full GC,若是小於檢查HandlePromotionFailure設置,若是true則只進行Monitor GC,若是false則進行Full GC。