您好,登錄后才能下訂單哦!
這篇文章主要講解了“Java的垃圾回收器有哪些”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Java的垃圾回收器有哪些”吧!
我們先回顧一下主流Java的垃圾回收器(HotSpot JVM)。本文是針對(duì)堆的垃圾回收展開討論的。 堆被分解為較小的三個(gè)部分。具體分為:新生代、老年代、持久代。
絕大部分新生成的對(duì)象都放在Eden區(qū),當(dāng)Eden區(qū)將滿,JVM會(huì)因申請不到內(nèi)存,而觸發(fā)Young GC ,進(jìn)行Eden區(qū)+有對(duì)象的Survivor區(qū)(設(shè)為S0區(qū))垃圾回收,把存活的對(duì)象用復(fù)制算法拷貝到一個(gè)空的Survivor(S1)中,此時(shí)Eden區(qū)被清空,另外一個(gè)Survivor S0也為空。下次觸發(fā)Young GC回收Eden+S0,將存活對(duì)象拷貝到S1中。新生代垃圾回收簡單、粗暴、高效。
若發(fā)現(xiàn)Survivor區(qū)滿了,則將這些對(duì)象拷貝到old區(qū)或者Survivor沒滿但某些對(duì)象足夠Old,也拷貝到Old區(qū)(每次Young GC都會(huì)使Survivor區(qū)存活對(duì)象值+1,直到閾值)。 Old區(qū)也會(huì)進(jìn)行垃圾收集(Young GC),發(fā)生一次 Major GC 至少伴隨一次Young GC,一般比Young GC慢十倍以上。
JVM在Old區(qū)申請不到內(nèi)存,會(huì)進(jìn)行Full GC。Old區(qū)使用一般采用Concurrent-Mark–Sweep策略回收內(nèi)存。 總結(jié):Java垃圾回收器是一種“自適應(yīng)的、分代的、停止—復(fù)制、標(biāo)記-清掃”式的垃圾回收器 缺點(diǎn):
GC過程中會(huì)出現(xiàn)STW(Stop-The-World),若Old區(qū)對(duì)象太多,STW耗費(fèi)大量時(shí)間。
CMS收集器對(duì)CPU資源很敏感。
CMS收集器無法處理浮動(dòng)垃圾,可能出現(xiàn)“Concurrent Mode Failure”失敗而導(dǎo)致另一次Full GC的產(chǎn)生。
CMS導(dǎo)致內(nèi)存碎片問題
#比較
Serial收集器
Serial收集器是JAVA虛擬機(jī)中最基本、歷史最悠久的收集器,在JDK 1.3.1之前是JAVA虛擬機(jī)新生代收集的唯一選擇。Serial收集器是一個(gè)單線程的收集器,但它的“單線程”的意義并不僅僅是說明它只會(huì)使用一個(gè)CPU或一條收集線程去完成垃圾收集工作,更重要的是在它進(jìn)行垃圾收集時(shí),必須暫停其他所有的工作線程,直到它收集結(jié)束。 Serial收集器到JDK1.7為止,它依然是JAVA虛擬機(jī)運(yùn)行在Client模式下的默認(rèn)新生代收集器。它也有著優(yōu)于其他收集器的地方:簡單而高效(與其他收集器的單線程比),對(duì)于限定單個(gè)CPU的環(huán)境來說,Serial收集器由于沒有線程交互的開銷,專心做垃圾收集自然可以獲得最高的單線程收集效率。在用戶的桌面應(yīng)用場景中,分配給虛擬機(jī)管理的內(nèi)存一般來說不會(huì)很大,收集幾十兆甚至一兩百兆的新生代(僅僅是新生代使用的內(nèi)存,桌面應(yīng)用基本上不會(huì)再大了),停頓時(shí)間完全可以控制在幾十毫秒最多一百多毫秒以內(nèi),只要不是頻繁發(fā)生,這點(diǎn)停頓是可以接受的。所以,Serial收集器對(duì)于運(yùn)行在Client模式下的虛擬機(jī)來說是一個(gè)很好的選擇。
PS:開啟Serial收集器的方式 -XX:+UseSerialGC 如:Xms30m -Xmx30m -Xmn10m -XX:+UseSerialGC -XX:+PrintGCDetails -XX:+UseSerialGC的是Serial收集器,Xms30m -Xmx30m 指定了JAVA虛擬機(jī)的固定大小為30M,-Xmn10m 指JAVA新生代的空間為10M。
Parallel(并行)收集器
這是 JVM 的缺省收集器。就像它的名字,其最大的優(yōu)點(diǎn)是使用多個(gè)線程來通過掃描并壓縮堆。串行收集器在GC時(shí)會(huì)停止其他所有工作線程(stop-the-world),CPU利用率是最高的,所以適用于要求高吞吐量(throughput)的應(yīng)用,但停頓時(shí)間(pause time)會(huì)比較長,所以對(duì)web應(yīng)用來說就不適合,因?yàn)檫@意味著用戶等待時(shí)間會(huì)加長。而并行收集器可以理解是多線程串行收集,在串行收集基礎(chǔ)上采用多線程方式進(jìn)行GC,很好的彌補(bǔ)了串行收集的不足,可以大幅縮短停頓時(shí)間(如下圖表示的停頓時(shí)長高度,并發(fā)比并行要短),因此對(duì)于空間不大的區(qū)域(如young generation),采用并行收集器停頓時(shí)間很短,回收效率高,適合高頻率執(zhí)行。 圖1.Serial收集器與Parallel/ Throughput(并行)收集器的比較
CMS收集器
CMS(Concurrent Mark Sweep)收集器是基于“標(biāo)記-清除”算法實(shí)現(xiàn)的,它使用多線程的算法去掃描堆(標(biāo)記)并對(duì)發(fā)現(xiàn)的未使用的對(duì)象進(jìn)行回收(清除)。整個(gè)過程分為6個(gè)步驟,包括: 初始標(biāo)記(CMS initial mark)
并發(fā)標(biāo)記(CMS concurrent mark)
并發(fā)預(yù)清理(CMS-concurrent-preclean)
重新標(biāo)記(CMS remark)
并發(fā)清除(CMS concurrent sweep)
并發(fā)重置(CMS-concurrent-reset)
其中初始標(biāo)記、重新標(biāo)記這兩個(gè)步驟仍然需要“Stop The World”。
初始標(biāo)記僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對(duì)象,速度很快
并發(fā)標(biāo)記階段就是進(jìn)行GC Roots Tracing的過程
重新標(biāo)記階段則是為了修正并發(fā)標(biāo)記期間,因用戶程序繼續(xù)運(yùn)作而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄,這個(gè)階段的停頓時(shí)間一般會(huì)比初始標(biāo)記階段稍長一些,但遠(yuǎn)比并發(fā)標(biāo)記的時(shí)間短。其他動(dòng)作都是并發(fā)的。
需要注意的是,CMS收集器無法處理浮動(dòng)垃圾(Floating Garbage),可能出現(xiàn)“Concurrent Mode Failure”失敗而導(dǎo)致另一次Full GC的產(chǎn)生。由于CMS并發(fā)清理階段用戶線程還在運(yùn)行著,伴隨程序的運(yùn)行自然還會(huì)有新的垃圾不斷產(chǎn)生,這一部分垃圾出現(xiàn)在標(biāo)記過程之后,CMS無法在本次收集中處理掉它們,只好留待下一次GC時(shí)再將其清理掉。這一部分垃圾就稱為“浮動(dòng)垃圾”。也是由于在垃圾收集階段用戶線程還需要運(yùn)行,即還需要預(yù)留足夠的內(nèi)存空間給用戶線程使用,因此CMS收集器不能像其他收集器那樣等到老年代幾乎完全被填滿了再進(jìn)行收集,需要預(yù)留一部分空間提供并發(fā)收集時(shí)的程序運(yùn)作使用。在默認(rèn)設(shè)置下,CMS收集器在老年代使用了68%的空間后就會(huì)被激活,這是一個(gè)偏保守的設(shè)置,如果在應(yīng)用中老年代增長不是太快,可以適當(dāng)調(diào)高參數(shù)-XX:CMSInitiatingOccupancyFraction的值來提高觸發(fā)百分比,以便降低內(nèi)存回收次數(shù)以獲取更好的性能。要是CMS運(yùn)行期間預(yù)留的內(nèi)存無法滿足程序需要,就會(huì)出現(xiàn)一次“Concurrent Mode Failure”失敗,這時(shí)候虛擬機(jī)將啟動(dòng)后備預(yù)案:臨時(shí)啟用Serial Old收集器來重新進(jìn)行老年代的垃圾收集,這樣停頓時(shí)間就很長了。所以說參數(shù)-XX:CMSInitiatingOccupancyFraction設(shè)置得太高將會(huì)很容易導(dǎo)致大量“Concurrent Mode Failure”失敗,性能反而降低。
還有一個(gè)缺點(diǎn),CMS是一款基于“標(biāo)記-清除”算法實(shí)現(xiàn)的收集器,這意味著收集結(jié)束時(shí)會(huì)產(chǎn)生大量空間碎片??臻g碎片過多時(shí),將會(huì)給大對(duì)象分配帶來很大的麻煩,往往會(huì)出現(xiàn)老年代還有很大的空間剩余,但是無法找到足夠大的連續(xù)空間來分配當(dāng)前對(duì)象,不得不提前觸發(fā)一次Full GC。為了解決這個(gè)問題,CMS收集器提供了一個(gè)-XX:+UseCMSCompactAtFullCollection開關(guān)參數(shù),用于在“享受”完Full GC服務(wù)之后額外免費(fèi)附送一個(gè)碎片整理過程,內(nèi)存整理的過程是無法并發(fā)的??臻g碎片問題沒有了,但停頓時(shí)間不得不變長了。虛擬機(jī)設(shè)計(jì)者們還提供了另外一個(gè)參數(shù)-XX: CMSFullGCsBeforeCompaction,這個(gè)參數(shù)用于設(shè)置在執(zhí)行多少次不壓縮的Full GC后,跟著來一次帶壓縮的。
該算法與并行收集器的另一個(gè)缺點(diǎn)是吞吐量的它使用更多的 CPU,為了使應(yīng)用程序提供更好的體驗(yàn),通過使用多個(gè)線程來執(zhí)行掃描和收集。這種情況長時(shí)間的運(yùn)行會(huì)使應(yīng)用程序停頓下來,可以使用提高空間來換取高效的運(yùn)行。但是,這種算法的使用不是默認(rèn)的。您必須指定 XX: + USeParNewGC來使用它。如果你可以提供更多的CPU資源的話以避免應(yīng)用程序暫停,那么你可以使用CMS收集器。假設(shè)你的堆的大小小于 4 Gb你必須分配大于 4 GB的資源。
G1收集器
G1垃圾收集器在JDK7 update 4之后對(duì)大于4G的堆有了更好的支持,G1是一個(gè)針對(duì)多處理器大容量內(nèi)存的服務(wù)器端的垃圾收集器,其目標(biāo)是在實(shí)現(xiàn)高吞吐量的同時(shí),盡可能的滿足垃圾收集暫停時(shí)間的要求。G1在執(zhí)行一些Java堆空間中的全區(qū)域操作(如:全局標(biāo)記)時(shí)是和應(yīng)用程序線程并發(fā)進(jìn)行的,因此減少了Java堆空間的中斷比例。(譯者注:可簡單理解為減少了Stop-the-World的時(shí)間比例)。
它與前面的CMS收集器相比有兩個(gè)顯著的改進(jìn):一是G1收集器是基于“標(biāo)記-整理”算法實(shí)現(xiàn)的收集器,也就是說它不會(huì)產(chǎn)生空間碎片,這對(duì)于長時(shí)間運(yùn)行的應(yīng)用系統(tǒng)來說非常重要。二是它可以非常精確地控制停頓,既能讓使用者明確指定在一個(gè)長度為M毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間不得超過N毫秒,具備了一些實(shí)時(shí)Java(RTSJ)的垃圾收集器的特征。
首先將Java堆空間劃分為一些大小相等的區(qū)域(region),每個(gè)區(qū)域都是虛擬機(jī)中的一段連續(xù)內(nèi)存空間。G1通過執(zhí)行并發(fā)的全局標(biāo)記來確定整個(gè)Java堆空間中存活的對(duì)象。標(biāo)記階段完成后,G1就知道哪些區(qū)域基本上是空閑的。在回收內(nèi)存時(shí)優(yōu)先回收這些區(qū)域,這樣通常都會(huì)回收相當(dāng)數(shù)量的內(nèi)存。這就是為什么它叫做Garbage-First的原因。顧名思義G1關(guān)注某些區(qū)域的回收和整理,這些區(qū)域中的對(duì)象很有可能被完全回收。而且G1使用了一個(gè)暫停時(shí)間預(yù)測模型使得暫停時(shí)間控制在用戶指定的暫停時(shí)間內(nèi),并根據(jù)用戶指定的暫停時(shí)間來選擇合適的區(qū)域回收內(nèi)存。
G1確定了可回收的區(qū)域后就是篩選回收(evacuation)階段了。在此階段將對(duì)象從一個(gè)或多個(gè)區(qū)域復(fù)制到單一區(qū)域,同時(shí)整理和釋放內(nèi)存。該階段是在多個(gè)處理器上多個(gè)線程并行進(jìn)行的,因此減少了暫停時(shí)間并提高了吞吐量。G1在每一次的垃圾收集過程中都不斷地減少碎片,并能夠?qū)和r(shí)間控制在一定范圍內(nèi)。這些已經(jīng)是以前的垃圾收集器無法完成的了。比如:CMS收集器并不做內(nèi)存整理。ParallelOld收集器只是對(duì)整個(gè)Java堆空間做整理,這樣導(dǎo)致相當(dāng)長的暫停時(shí)間。
感謝各位的閱讀,以上就是“Java的垃圾回收器有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)Java的垃圾回收器有哪些這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。