Full GC 就是收集整個堆,包括新生代,老年代,永久代(在JDK 1.8及之後,永久代會被移除,換爲metaspace)等收集全部部分的模式html
RednaxelaFX大在Major GC和Full GC的區別是什麼?觸發條件呢?- 知乎這個問題有關於 GC分類的回答:算法
針對 HotSpot VM的實現,它裏面的GC其實準確分類有兩種:segmentfault
針對不一樣的垃圾收集器,Full GC的觸發條件可能不都同樣。按HotSpot VM的serial GC的實現來看,觸發條件是:數組
當準備要觸發一次 young GC時,若是發現統計數聽說以前 young GC的平均晉升大小比目前的 old gen剩餘的空間大,則不會觸發young GC而是轉爲觸發 full GC (由於HotSpot VM的GC裏,除了垃圾回收器 CMS的concurrent collection 以外,其餘能收集old gen的GC都會同時收集整個GC堆,包括young gen,因此不須要事先準備一次單獨的young GC)網絡
若是有永久代(perm gen),要在永久代分配空間但已經沒有足夠空間時,也要觸發一次 full GC併發
System.gc(),heap dump帶GC,其默認都是觸發 full GC.jvm
HotSpot VM裏其餘非併發GC的觸發條件複雜一些,不過大體原理與上面說的其實同樣。性能
而在 Parallel Scavenge 收集器下,默認是在要觸發 full GC前先執行一次 young GC,而且兩次GC之間能讓應用程序稍微運行一小下,以期下降 full GC的暫停時間 (由於 young GC 會盡可能清理了young gen的死對象,減小了 full GC的工做量)。控制這個行爲的VM參數是: -XX:+ScavengeBeforeFullGC。優化
併發GC的觸發條件就不同,以 CMS GC爲例,它主要是定時去檢查old gen的使用量,但使用量超過了觸發比例就會啓動一次 CMS GC,對old gen作併發收集。spa
Minor GC 是俗稱,新生代(新生代分爲一個 Eden區和兩個Survivor區)的垃圾收集叫作 Minor GC。在 Oracle 高級研究員鄭雨迪的極客時間專欄 《深刻拆解Java虛擬機》中也談到 Minor GC,內容以下:
當 Eden 區的空間耗盡了怎麼辦?這個時候 Java虛擬機便會觸發一次 Minor GC來收集新生代的垃圾,存活下來的對象,則會被送到 Survivor區。
簡單說就是當新生代的Eden區滿的時候觸發 Minor GC
前面提到,新生代共有 兩個 Survivor區,咱們分別用 from 和 to來指代。其中 to 指向的Survivor區是空的。
當發生 Minor GC時,Eden 區和 from 指向的 Survivor 區中的存活對象會被複制(此處採用標記 - 複製算法)到 to 指向的 Survivor區中,而後交換 from 和 to指針,以保證下一次 Minor GC時,to 指向的 Survivor區仍是空的。
注意: from與to只是兩個指針,它們變更的,to指針指向的Survivor區是空的
Java虛擬機會記錄 Survivor區中的對象一共被來回複製了幾回。若是一個對象被複制的次數爲 15 (對應虛擬機參數 -XX:+MaxTenuringThreshold),那麼該對象將被晉升爲至老年代,(至於爲何是 15次,緣由是 HotSpot會在對象頭的中的標記字段裏記錄年齡,分配到的空間只有4位,因此最多隻能記錄到15)。另外,若是單個 Survivor 區已經被佔用了 50% (對應虛擬機參數: -XX:TargetSurvivorRatio),那麼較高複製次數的對象也會被晉升至老年代。
當Survivor區的部分對象晉升到老年代後,老年代的佔用量一般會升高。
注意:
在Minor GC過程當中,Survivor 可能不足以容納Eden和另外一個Survivor中的存活對象。若是Survivor中的存活對象溢出,多餘的對象將被移到老年代,這稱爲過早提高(Premature Promotion),這會致使老年代中短時間存活對象的增加,可能會引起嚴重的性能問題。再進一步說,在Minor GC過程當中,若是老年代滿了而沒法容納更多的對象,Minor GC 以後一般就會進行Full GC,這將致使遍歷整個Java堆,這稱爲提高失敗(Promotion Failure)。至於解決辦法,這就涉及到對應用程序的調優問題了,這裏就不敘述了,若有興趣,請自行查閱相關資料
Minor GC存在一個問題就是,老年代的對象可能引用新生代的對象,在標記存活對象的時候,就須要掃描老年代的對象,若是該對象擁有對新生代對象的引用,那麼這個引用也會被做爲 GC Roots。這至關於就作了全堆掃描。
HotSpot 給出的解決方案是 一項叫作 卡表 的技術。以下圖所示:
卡表的具體策略是將老年代的空間分紅大小爲 512B的若干張卡,而且維護一個卡表,卡表本省是字節數組,數組中的每一個元素對應着一張卡,其實就是一個標識位,這個標識位表明對應的卡是否可能存有指向新生代對象的引用,若是可能存在,那麼咱們認爲這張卡是髒的,即髒卡。如上圖所示,卡表3被標記爲髒。
在進行Minor GC的時候,咱們即可以不用掃描整個老年代,而是在卡表中尋找髒卡,並將髒卡中的老年代指向新生代的引用加入到 Minor GC的GC Roots裏,當完成全部髒卡的掃描以後,Java 虛擬機便會將全部髒卡的標識位清零。這樣虛擬機以空間換時間,避免了全表掃描
除了Full GC和Minor GC外,還有一種說法叫作 "Major GC":
Major GC一般是跟full GC是等價的,收集整個GC堆,但由於 HotSpot VM發展這麼多年,外界對各類名詞的解讀已經徹底混亂了,當有人說"Major GC"的時候必定要問清楚他想要指的是上面的 full GC仍是 old GC
以上是 R大關於 Major GC的說法,比較權威的。在網上還流行着另一種說法就是 Major GC是對老年代的垃圾回收。
以上的內容基本上是從 R大的知乎回答與極客時間專欄 《深刻拆解Java虛擬機》總結來的,在總結過程當中,也算是對 Full GC 與 Minor GC 有了一個基本的認識。
取之網絡,再回饋之網絡,本人對於JVM是渣渣級選手,若有錯誤之處,歡迎指教