深刻理解JVM(五)——垃圾回收器

 上一篇介紹了常見的垃圾回收算法,不一樣的算法各有各的優缺點,在JVM中並非單純的使用某一種算法進行垃圾回收,而是將不一樣的垃圾回收算法包裝在不一樣的垃圾回收器當中,用戶能夠根據自身的需求,使用不一樣的垃圾回收器,以便讓本身的java程序性能到達最佳。java

在介紹垃圾回收器以前,先回顧一下java堆的結構。算法

clip_image002

java堆內存結構包括:新生代和老年代,其中新生代由一個伊甸區和2個倖存區組成,2個倖存區是大小相同,徹底對稱的,沒有任何差異。咱們把它們稱爲S0區和S1區,也能夠稱爲from區和to區。多線程

JVM的垃圾回收主要是針對以上堆空間的垃圾回收,固然其實也會針對元數據區(永久區)進行垃圾回收,在此主要介紹對堆空間的垃圾回收。併發

下面介紹幾種垃圾回收器:性能

串行收集器

顧名思義,串行收集器就是使用單線程進行垃圾回收。對新生代的回收使用複製算法,對老年代使用標記壓縮算法,這也和上一篇介紹的算法優點是相吻合的。測試

串行收集器是最古老最穩定的收集器,儘管它是串行回收,回收時間較長,但其穩定性是優於其餘回收器的,綜合來講是一個不錯的選擇。要使用串行收集器,能夠在啓動配置時加上如下參數:spa

-XX:+UseSerialGC.net

串行回收器的執行流程以下所示:線程

clip_image004

執行垃圾回收時,應用程序線程暫停,GC線程開始(開始垃圾回收),垃圾回收完成後,應用程序線程繼續執行。注意:在GC線程運行過程當中使用單線程進行串行回收。設計

並行回收器

並行回收器就是使用多線程並行回收,不過這裏須要注意的是,針對新生代和老年代,是否都使用並行,有不一樣的回收器選擇:

一、 ParNew回收器

這個回收器只針對新生代進行併發回收,老年代依然使用串行回收。回收算法依然和串行回收同樣,新生代使用複製算法,老年代使用標記壓縮算法。在多核條件下,它的性能顯然優於串行回收器,若是要使用這種回收器,能夠在啓動參數中配置:

-XX:+UseParNewGC

若是要進一步指定併發的線程數,能夠配置一下參數:

-XX:ParallelGCThreads

ParNew回收器的流程以下圖所示:

clip_image006

在進行垃圾回收時應用程序線程依然被暫停,GC線程並行開始執行垃圾回收,垃圾回收完成後,應用程序線程繼續執行。

二、 Parallel回收器

依然是並行回收器,但這種回收器有兩種配置,一種相似於ParNEW:新生代使用並行回收、老年代使用串行回收。它與ParNew的不一樣在於它在設計目標上更重視吞吐量,能夠認爲在相同的條件下它比ParNew更優。要使用這種回收器能夠在啓動程序中配置:

-XX:+UseParallelGC

Parallel回收器另一種配置則不一樣於ParNew,對於新生代和老年代均適應並行回收,要使用這種回收器能夠在啓動程序中配置:

XX:+UseParallelOldGC

Parallel回收器的流程和ParNew的流程是一致的:

在進行回收時,應用程序暫停,GC使用多線程併發回收,回收完成後應用程序線程繼續運行。

CMS回收器

CMS回收器: Concurrent Mark Sweep,併發標記清除。注意這裏注意兩個詞:併發、標記清除。

並發表示它能夠與應用程序併發執行、交替執行;標記清除表示這種回收器不是使用的是標記壓縮算法,這和前面介紹的串行回收器和併發回收器有所不一樣。須要注意的是CMS回收器是一種針對老年代的回收器,不對新生代產生做用這種回收器優勢在於減小了應用程序停頓的時間,由於它不須要應用程序完成暫定等待垃圾回收,而是與垃圾回收併發執行。要執行這種垃圾回收器能夠在啓動參數中配置:

-XX:+UseConcMarkSweepGC

CMS回收機運行機制很是複雜,咱們簡單的將他的運行流程分爲如下幾步:

初始標記

標記從GC Root能夠直接可達的對象;

併發標記(和應用程序線程一塊兒)

主要標記過程,標記所有對象;

從新標記

因爲併發標記時,用戶線程依然運行,所以在正式清理前,再作依次從新標記,進行修正。

併發清除(和用戶線程一塊兒)

基於標記結果,直接清理對象。

流程以下圖所示:

clip_image010

從上圖能夠看到標記過程分三步:初始標記、併發標記、從新標記,併發標記是最主要的標記過程,而這個過程是併發執行的,能夠與應用程序線程同時進行,初始標記和從新標記雖然不能和應用程序併發執行,但這兩個過程標記速度快,時間短,因此對應用程序不會產生太大的影響。最後併發清除的過程,也是和應用程序同時進行的,避免了應用程序的停頓。

CMS的優勢顯而易見,就是減小了應用程序的停頓時間,讓回收線程和應用程序線程能夠併發執行。但它也不是完美的,從他的運行機制能夠看出,由於它不像其餘回收器同樣集中一段時間對垃圾進行回收,而且在回收時應用程序仍是運行,所以它的回收並不完全。這也致使了CMS回收的頻率相較其餘回收器要高,頻繁的回收將影響應用程序的吞吐量。

G1回收器

G1回收器是jdk1.7之後推出的回收器,試圖取代CMS回收器。

不一樣於其餘的回收器、G1將堆空間劃分紅了互相獨立的區塊。每塊區域既有可能屬於老年代、也有多是新生代,而且每類區域空間能夠是不連續的(對比CMS的老年代和新生代都必須是連續的)。這種將老年代區劃分紅多塊的理念源於:當併發後臺線程尋找可回收的對象時、有些區塊包含可回收的對象要比其餘區塊多不少。雖然在清理這些區塊時G1仍然須要暫停應用線程、但能夠用相對較少的時間優先回收包含垃圾最多區塊。這也是爲何G1命名爲Garbage First的緣由:第一時間處理垃圾最多的區塊。要使用G1回收器須要在啓動是配置如下參數:

-XX:+UseG1GC

G1相對CMS回收器來講優勢在於:

一、由於劃分了不少區塊,回收時減少了內存碎片的產生;

二、G1適用於新生代和老年代,而CMS只適用於老年代。

小結

    本文簡要介紹了JVM中的垃圾回收器,主要包括串行回收器、並行回收器以及CMS回收器、G1回收器。他們各自都有優缺點,一般來講須要根據業務,進行基於垃圾回收器的性能測試,而後再作選擇。下面給出配置回收器時,常用的參數:

-XX:+UseSerialGC:在新生代和老年代使用串行收集器

-XX:+UseParNewGC:在新生代使用並行收集器

-XX:+UseParallelGC :新生代使用並行回收收集器,更加關注吞吐量

-XX:+UseParallelOldGC:老年代使用並行回收收集器

-XX:ParallelGCThreads:設置用於垃圾回收的線程數

-XX:+UseConcMarkSweepGC:新生代使用並行收集器,老年代使用CMS+串行收集器

-XX:ParallelCMSThreads:設定CMS的線程數量

-XX:+UseG1GC:啓用G1垃圾回收器

相關文章
相關標籤/搜索