什麼情況下會發生full Gc?如何排查頻繁發生full Gc的原因?

GC就是Java的垃圾回收機制,要了解什麼情況下會發生GC(即GC得觸發條件),我們需要先了解JVM的內存模型結構,之前一篇文章已經詳細講解了Jvm的內存模型結構,而通常來說,GC主要針對的是堆(java heap)區。

而java heap是分代的(年輕代和老年代),爲什麼要分代?其實也不難理解,分代就是爲了優化性能,如果不分代,那就會導致所有對象揉在一塊,那樣GC就會對堆區域進行全掃描。所以,分代可以大大提升GC性能,那麼,分代的原理是什麼?

JVM對於堆的垃圾回收,採用分代收集的策略,所以分代的原理就是根據堆中對象的存活週期進行分代,年輕代中,每次垃圾回收都有大批對象死去,只有少量存活,而老年代中存放的對象存活率高。

>>>>>年輕代<<<<<
Jvm把年輕代分三部分:1個Eden(伊甸園)區和2個Survivor(倖存者)區(分別叫from和to),默認比例爲8:1。

爲啥默認這個比例?
一般情況下,新創建的對象都會被分配到Eden區(一些大對象特殊處理),這些對象經過第一次Minor GC後,如果仍然存活,將會被移到Survivor區。對象在Survivor區中每熬過一次Minor GC,年齡就會增加1歲,當它的年齡增加到一定程度(默認15歲)時,就會被移動到年老代中。

因爲年輕代中的對象基本都是朝生夕死的(80%以上),所以年輕代的垃圾回收算法採用複製算法(內存分爲兩塊,每次只用其中一塊,當一塊內存用完,就將還活着的對象複製到另外一塊內存上,複製算法不產生內存碎片)。在GC開始的時候,對象只會存在於Eden區和名爲“From”的Survivor區,Survivor區“To”是空的。緊接着進行GC,Eden區中所有存活的對象都會被複制到“To”,而在“From”區中,仍存活的對象會根據他們的年齡值來決定去向。年齡達到一定值(年齡閾值,可以通過-XX:MaxTenuringThreshold來設置)的對象會被移動到年老代中,沒有達到閾值的對象會被複制到“To”區域。經過這次GC後,Eden區和From區已經被清空。

這個時候,“From”和“To”會交換他們的角色,就是新的“To”是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎樣,都會保證名爲To的Survivor區域是空的。Minor GC會一直重複這樣的過程,直到“To”區被填滿,“To”區被填滿之後,會將所有對象移動到年老代中。

總結下來,JVM的堆區對象分配的規則一般如下:
1)對象優先在Eden區分配

2)大對象直接進入老年代(-XX:PretenureSizeThreshold=3145728 該參數來定義進入老年代對象大小)

3)長期存活的對象將進入老年代(在JDK8中-XX:MaxTenuringThreshold=1的閥值設定根本沒用)

4)動態對象年齡判定(虛擬機並不會永遠地要求對象的年齡都必須達到MaxTenuringThreshold才能晉升老年代,如果Survivor空間中相同年齡的所有對象的大小總和大於Survivor的一半,年齡大於或等於該年齡的對象就可以直接進入老年代)

5)空間分配擔保

6)只要老年代的連續空間大於(新生代所有對象的總大小或者歷次晉升的平均大小)就會進行minor GC,否則會進行full GC

GC的觸發條件
PS:JVM優化的目的就是減少SWT執行的時間(避免卡頓),避免頻繁full gc
1)System.gc()方法的調用。
此方法的調用是建議JVM進行Full GC,雖然只是建議而非一定,但很多情況下它會觸發 Full GC,從而增加Full GC的頻率,也即增加了間歇性停頓的次數。強烈影響系建議能不使用此方法就別使用,讓虛擬機自己去管理它的內存,可通過通過-XX:+ DisableExplicitGC來禁止RMI(Java遠程方法調用)調用System.gc。

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

3)Permanet Generation空間滿了。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。

4)通過Minor GC後進入老年代的平均大小大於老年代的可用內存

5)由Eden區、From Space區向To Space區複製時,對象大小大於To Space可用內存,則把該對象轉存到老年代,且老年代可用內存不足(老年代可用內存小於該對象)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章