閱讀661 返回首頁    go 阿裏雲 go 技術社區[雲棲]


我眼中的G1 GC

  7歲那年,當我合上《上下五千年》一套三冊全書時,我對自己說,我想當個作家。這一晃27年了,等待了27年,我的第一本書《大話Java性能優化》在2016年4月正式麵世,2016年8月第二次印刷,2017年5月第三次印刷,感謝讀者的厚愛。《深入理解JVM&G1 GC》這本書是我的第二本書,也即將麵世。對於我的每一本書,我都懷著忐忑、驚喜的心情,就像第一次麵對我的女兒“小頑子”,給她取這個小名,希望她頑強到底,因為我相信,你若頑強到底,一切皆有可能。

  我喜歡看書,每年購買的書接近100本,也喜歡對技術進行積累。一直沒有出書的想法,直到遇到了電子工業出版社的董老師,在深圳南湖的一席暢談後,我決定做一位業餘的技術作家,致力於中國軟件開發行業的技術推廣、普及、推動。

  這本書是介紹JVM和G1 GC的,讓我們回憶一下。還記得哆啦A夢嗎?他和大熊有一張書桌,書桌的抽屜其實是一個時空穿梭通道,現在讓我們來掌控這個時空機器,回到1998年。那年的12月8日,第二代Java平台的企業版J2EE正式對外發布。為了配合企業級應用落地,1999年4月27日,Java程序的舞台—Java HotSpot Virtual Machine(以下簡稱HotSpot )正式對外發布,並從這之後發布的JDK1.3版本開始,HotSpot成為Sun JDK的默認虛擬機。
            圖片描述

GC發展曆史簡介

  1999年隨JDK1.3.1一起來的是串行方式的Serial GC ,它是第一款GC,並且這隻是起點。此後,JDK1.4和J2SE1.3相繼發布。2002年2月26日,J2SE1.4發布,Parallel GC 和Concurrent Mark Sweep (CMS)GC跟隨JDK1.4.2一起發布,並且Parallel GC在JDK6之後成為HotSpot默認GC。

  HotSpot有這麼多的垃圾回收器,那麼如果有人問,Serial GC、Parallel GC、Concurrent Mark Sweep GC這三個GC有什麼不同呢?請記住以下口令:

  • 如果你想要最小化地使用內存和並行開銷,請選Serial GC;
  • 如果你想要最大化應用程序的吞吐量,請選Parallel GC;
  • 如果你想要最小化GC的中斷或停頓時間,請選CMS GC。

那麼問題來了,既然我們已經有了上麵三個強大的GC,為什麼還要發布Garbage First(G1)GC?原因就在於應用程序所應對的業務越來越龐大、複雜,用戶越來越多,沒有GC就不能保證應用程序正常進行,而經常造成STW的GC又跟不上實際的需求,所以才會不斷地嚐試對GC進行優化。

  為什麼名字叫做Garbage First(G1)呢?

  因為G1是一個並行回收器,它把堆內存分割為很多不相關的區間(Region),每個區間可以屬於老年代或者年輕代,並且每個年齡代區間可以是物理上不連續的。

 老年代區間這個設計理念本身是為了服務於並行後台線程,這些線程的主要工作是尋找未被引用的對象。而這樣就會產生一種現象,即某些區間的垃圾(未被引用對象)多於其他的區間。

  垃圾回收時實則都是需要停下應用程序的,不然就沒有辦法防治應用程序的幹擾 ,然後G1 GC可以集中精力在垃圾最多的區間上,並且隻會費一點點時間就可以清空這些區間裏的垃圾,騰出完全空閑的區間。

  繞來繞去終於明白了,由於這種方式的側重點在於處理垃圾最多的區間,所以我們給G1一個名字:垃圾優先(Garbage First)。

G1 GC基本思想

  G1 GC是一個壓縮收集器,它基於回收最大量的垃圾原理進行設計。G1 GC利用遞增、並行、獨占暫停這些屬性,通過拷貝方式完成壓縮目標。此外,它也借助並行、多階段並行標記這些方式來幫助減少標記、重標記、清除暫停的停頓時間,讓停頓時間最小化是它的設計目標之一。

  G1回收器是在JDK1.7中正式投入使用的全新的垃圾回收器,從長期目標來看,它是為了取代CMS 回收器。G1回收器擁有獨特的垃圾回收策略,這和之前提到的回收器截然不同。從分代上看,G1依然屬於分代型垃圾回收器,它會區分年輕代和老年代,年輕代依然有Eden區和Survivor區,但從堆的結構上看,它並不要求整個Eden區、年輕代或者老年代在物理上都是連續。

  綜合來說,G1使用了全新的分區算法,其特點如下所示:

  1. 並行性:G1在回收期間,可以有多個GC線程同時工作,有效利用多核計算能力;
  2. 並發性:G1擁有與應用程序交替執行的能力,部分工作可以和應用程序同時執行,因此,一般來說,不會在整個回收階段發生完全阻塞應用程序的情況;
  3. 分代GC:G1依然是一個分代收集器,但是和之前的各類回收器不同,它同時兼顧年輕代和老年代。對比其他回收器,或者工作在年輕代,或者工作在老年代;
  4. 空間整理:G1在回收過程中,會進行適當的對象移動,不像CMS隻是簡單地標記清理對象。在若幹次GC後,CMS必須進行一次碎片整理。而G1不同,它每次回收都會有效地複製對象,減少空間碎片,進而提升內部循環速度。
  5. 可預見性:由於分區的原因,G1可以隻選取部分區域進行內存回收,這樣縮小了回收的範圍,因此對於全局停頓情況的發生也能得到較好的控製。

隨著G1 GC的出現,GC從傳統的連續堆內存布局設計,逐漸走向不連續內存塊,這是通過引入Region概念實現,也就是說,由一堆不連續的Region組成了堆內存。其實也不能說是不連續的,隻是它從傳統的物理連續逐漸改變為邏輯上的連續,這是通過Region的動態分配方式實現的,我們可以把一個Region分配給Eden、Survivor、老年代、大對象區間、空閑區間等的任意一個,而不是固定它的作用,因為越是固定,越是呆板。

G1 GC垃圾回收機製

  通過市場的力量,不斷淘汰舊的行業,把有限的資源讓給那些競爭力更強、利潤率更高的企業。類似地,矽穀也在不斷淘汰過時的人員,從全世界吸收新鮮血液。經過半個多世紀的發展,在矽穀地區便形成隻有卓越才能生存的文化。本著這樣的理念,GC承擔了淘汰垃圾、保存優良資產的任務。

  G1 GC在回收暫停階段會回收最大量的堆內區間(Region),這是它的設計目標,通過回收區間達到回收垃圾的目的。這裏隻有一個例外情況,這個例外發生在並行標記階段的清除(Cleanup)步驟,如果G1 GC在清除步驟發現所有的區間都是由可回收垃圾組成的,那麼它會立即回收這些區間,並且將這些區間插入到一個基於LinkedList實現的空閑區間隊列裏,以待後用。因此,釋放這些區間並不需要等待下一個垃圾回收中斷,它是實時執行的,即清除階段起到了最後一道把控作用。這是G1 GC和之前的幾代GC的一大差別。

  G1 GC的垃圾回收循環由四個主要類型組成:

  • 年輕代循環
  • 多步驟並行標記循環
  • 混合收集循環
  • Full GC

在年輕代回收期,G1 GC暫停應用程序線程,然後從年輕代區間移動存活對象到Survivor區間或者老年區間,也有可能是兩個區間都會涉及。對於一個混合回收期,G1 GC從老年區間移動存活對象到空閑區間,這些空閑區間也就成為了老年代的一部分。

  技術方麵介紹到這裏,有興趣的讀者可以買一本看看。這本書主要為學習Java語言的學生、初級程序員提供JVM和GC的使用和優化建議及經驗交流,力求做到知識的綜合傳播,而不是僅僅隻針對Java虛擬機調優進行講解。本書具體來說包括以下幾方麵:JVM基礎知識、GC基礎知識、G1 GC深入介紹、G1 GC調優建議、JDK自帶工具使用介紹等。

  相關圖書推薦,《深入理解JVM & G1 GC》。
                      圖片描述
  想及時獲得更多精彩文章,可在微信中搜索“博文視點”或者掃描下方二維碼並關注。
                         圖片描述

最後更新:2017-06-22 10:32:09

  上一篇:go  《vSphere性能設計:性能密集場景下CPU、內存、存儲及網絡的最佳設計實踐》一1.7 小結
  下一篇:go  解讀 CSS 布局之水平垂直居中