爲解決CMS算法產生空間碎片和其它一系列的問題缺陷,HotSpot提供了另一種垃圾回收策略,G1(Garbage First)算法,經過參數 -XX:+UseG1GC
來啓用,該算法在JDK 7u4版本被正式推出算法
G1垃圾收集算法主要應用在多CPU大內存的服務中,在知足高吞吐量的同時,竟可能的知足垃圾回收時的暫停時間,該設計主要針對以下應用場景:(多CPU,大內存,高吞吐,儘量GC短暫暫停)併發
垃圾收集線程和應用線程併發執行,和CMS同樣性能
空閒內存壓縮時避免冗長的暫停時間ui
應用須要更多可預測的GC暫停時間spa
不但願犧牲太多的吞吐性能線程
不須要很大的Java堆 (翻譯的有點虛,多大才算大?)翻譯
在G1算法中,堆內存被劃分爲多個大小相等的內存塊(Region),每一個Region是邏輯連續的一段內存。設計
其它GC算法內存space必須是地址連續的空間。code
每一個Region被標記了E(eden)、S(survivor)、O(old)和H(humongous),對象
說明每一個Region在運行時都充當了一種角色,其中H是以往算法中沒有的,它表明Humongous,這表示這些Region存儲的是巨型對象(humongous object,H-obj),當新建對象大小超過Region大小一半時,直接在新的一個或多個連續Region中分配,並標記爲H。
堆內存中一個Region的大小能夠經過 -XX:G1HeapRegionSize
參數指定,大小區間只能是1M、2M、4M、8M、16M和32M,總之是2的冪次方,若是G1HeapRegionSize爲默認值,則在堆初始化時計算Region的實踐大小,默認把堆內存按照2048份均分,最後獲得一個合理的大小。
G1中提供了三種模式垃圾回收模式,young gc、mixed gc 和 full gc,在不一樣的條件下被觸發。
發生在年輕代的GC算法,通常對象(除了巨型對象)都是在eden region中分配內存,當全部eden region被耗盡沒法申請內存時,就會觸發一次young gc,這種觸發機制和以前的young gc差很少,執行完一次young gc,活躍對象會被拷貝到survivor region或者晉升到old region中,空閒的region會被放入空閒列表中,等待下次被使用。
當愈來愈多的對象晉升到老年代old region時,爲了不堆內存被耗盡,虛擬機會觸發一個混合的垃圾收集器,即mixed gc,該算法並非一個old gc,除了回收整個young region,還會回收一部分的old region,這裏須要注意:是一部分老年代,而不是所有老年代,能夠選擇哪些old region進行收集,從而能夠對垃圾回收的耗時時間進行控制。
那麼mixed gc何時被觸發?
先回顧一下cms的觸發機制,若是添加了如下參數:
-XX:CMSInitiatingOccupancyFraction=80
-XX:+UseCMSInitiatingOccupancyOnly
當老年代的使用率達到80%時,就會觸發一次cms gc。
相對的,mixed gc中也有一個閾值參數 -XX:InitiatingHeapOccupancyPercent
,當老年代大小佔整個堆大小百分比達到該閾值時,會觸發一次mixed gc.
mixed gc的執行過程有點相似cms,主要分爲如下幾個步驟:
initial mark: 初始標記過程,整個過程STW,標記了從GC Root可達的對象
concurrent marking: 併發標記過程,整個過程gc collector線程與應用線程能夠並行執行,標記出GC Root可達對象衍生出去的存活對象,並收集各個Region的存活對象信息
remark: 最終標記過程,整個過程STW,標記出那些在併發標記過程當中遺漏的,或者內部引用發生變化的對象
clean up: 垃圾清除過程,若是發現一個Region中沒有存活對象,則把該Region加入到空閒列表中
若是對象內存分配速度過快,mixed gc來不及回收,致使老年代被填滿,就會觸發一次full gc,G1的full gc算法就是單線程執行的serial old gc,會致使異常長時間的暫停時間,須要進行不斷的調優,儘量的避免full gc.
https://mp.weixin.qq.com/s/K7T8vjiHEwwN8uiXVLI6AQ
https://mp.weixin.qq.com/s/bHx0K4BRaHsmDSV0oxqf_Q