Java中的垃圾收集器
本系列為《深入理解Java虛擬機 》(周志明著)讀書筆記。
Java中的垃圾收集器
JVM規范對于垃圾收集器的實現沒有任何規定,因此不同廠商、版本的虛擬機所提供的垃圾收集器可能會有很大的差異。這里我們的討論將基于Sun Hotspot虛擬機1.6版Update22,此虛擬機包含的垃圾回收器如下圖:
上圖中共有HotSpot 1.6中共有7種垃圾回收器,如果兩個垃圾回收器之間有連線,說明二者可以搭配使用。下面我將對這些垃圾收集器一一進行介紹。
Serial收集器
Serial 是歷史最久的垃圾收集器之一,是一個單線程的收集器。它在進行垃圾收集時,必須暫停其他工作線程,直到它收集結束。Seiral收集器的垃圾回收過程是由 虛擬機在后臺發起和完成的,在用戶不可見的情況下暫停所有工作線程,這將帶來惡劣的用戶體驗,其工作原理如下圖所示:

Serial/Serial Old收集器運行示意圖
Serial 收集器盡管顯得“簡陋”并且用戶體驗不佳,但到1.6為止它仍然是虛擬機運行在Client模式下的默認新生代收集器。這主要得益于它的簡單高效,并且在 桌面應用中,分配給JVM管理的內存一般不會很大,收集幾十兆到一兩百兆的新生代,停頓時間完全可以控制住幾十毫秒最多一百多毫秒內,只要不是頻繁發生, 這點兒卡頓是完全可以接受的。
ParNew收集器
ParNew 收集器其實就是Serial收集器的多線程版本,除使用多線程收集職位,其余的行為包括收集算法、Stop the world、對象分配規則、回收策略等都與Serial收集器完全一樣,實際上這兩種收集器共用了很多代碼,ParNew收集器的工作原理如下圖所示:

ParNew/Serial Old收集器運行示意圖
ParNew是許多運行在Server模式下的虛擬機中首選的新生代收集器,其中一個重要原因是,除Serial收集器外,只有它能與CMS收集器配合工作。CMS是HotSpot虛擬機中第一款真正意義上的并發收集器,我們將在下面詳細討論CMS收集器。
垃圾收集器中的并發與并行
并行(Parallel):指多頭垃圾收集器線程并行工作,但此時用戶線程仍處于等待狀態。
并發(Concurrent):指用戶線程與回收器線程同時工作。
Parallel Scavenge收集器
Parallel Scavenge與ParNew很類似,是一個使用復制算法的新生代的并行多線程收集器。那么它與ParNew的區別在哪里?他們之間最大的區別是關注點 不一樣,ParNew等收集器的關注點在于盡可能地縮短垃圾收集時用戶線程的停頓時間,而Parallel Scavenge收集器的目標是達到一個可控制的吞吐量(Throughput)。
吞吐量指用于運行用戶代碼的CPU時間與總CPU時間的比值,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間 + 垃圾收集時間)。
Parallel Scavenge收集器的另一個特點是可以使用自適應的調節策略。使用這種策略,虛擬機會根據當前系統的運行情況收集性能監控信息,動態調整新生代大小、Eden與Survivor區的比例、晉升老年代對象年齡等細節參數。其工作過程如下圖所示:

Serial Old收集器
Serial Old是Serial收集器的老年代辦不,其工作過程如下圖所示:

Serial/Serial Old收集器運行示意圖
Parallel Old收集器
</div>Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和“標記 - 整理”算法,其工作過程如下圖所示:

CMS收集器
CMS(Concurrent Mark Sweep)收集器是基于“標記 - 清除”算法的并發收集器,其設計目標為獲取最短回收停頓時間。它的運作過程比上面介紹的收集器都要復雜一些,整個過程分為四個步驟,包括:
- 初始標記
- 并發標記
- 重新標記
- 并發清除 </ol>
- 對CPU資源非常敏感。幾乎所有的并行/并發系統都對CPU敏感。雖然它很少導致用戶卡頓,但是會因為占用了一部分線程而導致應用程序變慢,總吞吐量變低。
- 無 法處理浮動垃圾(Floating Garbage),可能出現“Concurrent Mode Failure”失敗而導致另一次Full GC的產生。由于CMS并發清理階段用戶線程還在同時執行,因此此時這些線程產生的這部分垃圾CMS無法處理,只好留在下一次GC時再清理,這一部分垃圾 就被稱為“浮動垃圾”。因為在垃圾收集階段用戶線程還在運行,因此CMS需要預留足夠的空間供這些線程使用,而不能向其他收集器那樣等老年代幾乎被完全充 滿時再進行回收。默認CMS收集器在老年代使用68%之后就被激活。
- 這個缺點來自于CMS所采用的“標記 - 清除”算法。這種方式容易產生大量碎片,當碎片過多時,容易出現老年代空間有很大剩余,但找不到連續空間進行分配給大對象,從而不得不提前觸發一次GC。 </ol>
- 采用“標記 - 整理”算法,避免產生碎片
- 可以精確地控制卡頓。這是通過讓使用指定一個參數來控制在一個長度為M的時間片內垃圾回收的時間N。 </ol> G1之所以可以在基本不犧牲吞吐量的前提下完成垃圾回收,是因為它能夠盡量避免全區域的垃圾回收。之前的收集器是進行收集的范圍是整個新生代或 老年代,而G1將整個Java堆(包括新生代、老年代)劃分為多個大小固定的獨立區域,并且跟蹤這些區域的堆積成都,在后臺維護一個優先列表,每次根據優 先級從列表中挑選區域進行收集。
初始標記和重新標記仍需暫停所有用戶線程,即Stop the World,但初始標記只是標記GC Roots能直接關聯的對象,而重新標記則只是為了修正并發標記期間,因用戶程序繼續運行而產生變動那一部分對象,這個階段的停頓時間比前面介紹的 Stop the World的時間要短得多。整個收集過程中耗時最久的并發標記和并發清除則和用戶線程一起工作,所以總地來講,CMS中GC線程是和用戶線程一起并發執行 的。下圖可以比較清楚地解釋這個過程:
</div>

CMS收集器運行示意圖
CMS是一款突破性的收集器,它極大地縮短了用戶線程停頓時間,可以認為其實現了并發垃圾回收,但金無足赤,人無完人,CMS還是具有這幾個缺陷:
G1 收集器
G1(Garbage First)收集器是當前收集器技術發展的最前沿成果,它與CMS相比會有兩個顯著改進:
轉自: http://blog.csdn.net/jubincn/article/details/8631571
本文由用戶 yg3n 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!