觸發JVM進行Full GC的狀況及應對策略

堆內存劃分爲 Eden、Survivor 和 Tenured/Old 空間,以下圖所示:java

從年輕代空間(包括 Eden 和 Survivor 區域)回收內存被稱爲 Minor GC,對老年代GC稱爲Major GC,而Full GC是對整個堆來講的,在最近幾個版本的JDK裏默認包括了對永生帶即方法區的回收(JDK8中無永生帶了),出現Full GC的時候常常伴隨至少一次的Minor GC,但非絕對的。Major GC的速度通常會比Minor GC慢10倍以上。下邊看看有那種狀況觸發JVM進行Full GC及應對策略。數組

 

一、System.gc()方法的調用併發

 

此方法的調用是建議JVM進行Full GC,雖然只是建議而非必定,但不少狀況下它會觸發 Full GC,從而增長Full GC的頻率,也即增長了間歇性停頓的次數。強烈影響系建議能不使用此方法就別使用,讓虛擬機本身去管理它的內存,可經過經過-XX:+ DisableExplicitGC來禁止RMI調用System.gc。spa


二、老年代代空間不足


老年代空間只有在新生代對象轉入及建立爲大對象、大數組時纔會出現不足的現象,當執行Full GC後空間仍然不足,則拋出以下錯誤:
java.lang.OutOfMemoryError: Java heap space 
爲避免以上兩種情況引發的Full GC,調優時應儘可能作到讓對象在Minor GC階段被回收、讓對象在新生代多存活一段時間及不要建立過大的對象及數組。

設計

三、永生區空間不足


JVM規範中運行時數據區域中的方法區,在HotSpot虛擬機中又被習慣稱爲永生代或者永生區,Permanet Generation中存放的爲一些class的信息、常量、靜態變量等數據,當系統中要加載的類、反射的類和調用的方法較多時,Permanet Generation可能會被佔滿,在未配置爲採用CMS GC的狀況下也會執行Full GC。若是通過Full GC仍然回收不了,那麼JVM會拋出以下錯誤信息:
java.lang.OutOfMemoryError: PermGen space 
爲避免Perm Gen佔滿形成Full GC現象,可採用的方法爲增大Perm Gen空間或轉爲使用CMS GC。
日誌


四、CMS GC時出現promotion failed和concurrent mode failure


對於採用CMS進行老年代GC的程序而言,尤爲要注意GC日誌中是否有promotion failed和concurrent mode failure兩種情況,當這兩種情況出現時可能
orm

會觸發Full GC。
promotion failed是在進行Minor GC時,survivor space放不下、對象只能放入老年代,而此時老年代也放不下形成的;concurrent mode failure是在
對象

執行CMS GC的過程當中同時有對象要放入老年代,而此時老年代空間不足形成的(有時候「空間不足」是CMS GC時當前的浮動垃圾過多致使暫時性的空間不足觸發Full GC)。
對措施爲:增大survivor space、老年代空間或調低觸發併發GC的比率,但在JDK 5.0+、6.0+的版本中有可能會因爲JDK的bug29致使CMS在remark完畢
內存

後好久才觸發sweeping動做。對於這種情況,可經過設置-XX: CMSMaxAbortablePrecleanTime=5(單位爲ms)來避免。ci


五、統計獲得的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。

 

六、堆中分配很大的對象

 

所謂大對象,是指須要大量連續內存空間的java對象,例如很長的數組,此種對象會直接進入老年代,而老年代雖然有很大的剩餘空間,可是沒法找到足夠大的連續空間來分配給當前對象,此種狀況就會觸發JVM進行Full GC。

爲了解決這個問題,CMS垃圾收集器提供了一個可配置的參數,即-XX:+UseCMSCompactAtFullCollection開關參數,用於在「享受」完Full GC服務以後額外免費贈送一個碎片整理的過程,內存整理的過程沒法併發的,空間碎片問題沒有了,但提頓時間不得不變長了,JVM設計者們還提供了另一個參數 -XX:CMSFullGCsBeforeCompaction,這個參數用於設置在執行多少次不壓縮的Full GC後,跟着來一次帶壓縮的。

相關文章
相關標籤/搜索