天天看點

我眼中的G1 GCGC發展曆史簡介G1 GC基本思想G1 GC垃圾回收機制

引言:本文作者周明耀,讓我們回到1998年,随作者從GC發展史開始一同重新了解G1 GC。

相關圖書推薦,《深入了解JVM & 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的預設虛拟機。

            

我眼中的G1 GCGC發展曆史簡介G1 GC基本思想G1 GC垃圾回收機制

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》。

                      

我眼中的G1 GCGC發展曆史簡介G1 GC基本思想G1 GC垃圾回收機制