jvm-垃圾回收

寫(xiě)在前面:


常見(jiàn)面試題:

  • 如何判斷對(duì)象是否死亡(兩種方法)颓鲜?
  • 簡(jiǎn)單的介紹一下強(qiáng)引用、軟引用陕贮、弱引用堕油、虛引用(虛引用與軟引用和弱引用的區(qū)別、使用軟引用能帶來(lái)的好處)肮之。
  • 如何判斷一個(gè)常量是廢棄常量掉缺?
  • 如何判斷一個(gè)類(lèi)是無(wú)用的類(lèi)?
  • 垃圾收集有哪些算法戈擒,各自的特點(diǎn)眶明?
  • HotSpot為什么要分為新生代和老年代?
  • 常見(jiàn)的垃圾回收器有那些筐高?
  • 介紹一下CMS,G1收集器搜囱。
  • Minor Gc和Full GC 有什么不同呢?

導(dǎo)火索:

當(dāng)需要排查各種 內(nèi)存溢出問(wèn)題柑土、當(dāng)垃圾回收成為系統(tǒng)達(dá)到更高并發(fā)的瓶頸時(shí)蜀肘,我們就需要對(duì)這些“自動(dòng)化”的技術(shù)實(shí)施必要的監(jiān)控和調(diào)節(jié)。

1.揭開(kāi)JVM內(nèi)存分配與回收的神秘面紗


Java 的自動(dòng)內(nèi)存管理主要是針對(duì)對(duì)象內(nèi)存的回收和對(duì)象內(nèi)存的分配冰单。同時(shí)幌缝,Java 自動(dòng)內(nèi)存管理最核心的功能是 堆 內(nèi)存中對(duì)象的分配與回收。

Java 堆是垃圾收集器管理的主要區(qū)域诫欠,因此也被稱作GC堆(Garbage Collected Heap).從垃圾回收的角度涵卵,由于現(xiàn)在收集器基本都采用分代垃圾收集算法,所以 Java 堆還可以細(xì)分為:新生代和老年代:再細(xì)致一點(diǎn)有:Eden空間荒叼、From Survivor轿偎、To Survivor空間等。進(jìn)一步劃分的目的是更好地回收內(nèi)存被廓,或者更快地分配內(nèi)存坏晦。
堆的基本結(jié)構(gòu)


上圖所示的 eden區(qū)、s0區(qū)嫁乘、s1區(qū)都屬于新生代昆婿,tentired 區(qū)屬于老年代。大部分情況蜓斧,對(duì)象都會(huì)首先在 Eden 區(qū)域分配仓蛆,在一次新生代垃圾回收后,如果對(duì)象還存活挎春,則會(huì)進(jìn)入 s0 或者 s1看疙,并且對(duì)象的年齡還會(huì)加 1(Eden區(qū)->Survivor 區(qū)后對(duì)象的初始年齡變?yōu)?)豆拨,當(dāng)它的年齡增加到一定程度(默認(rèn)為15歲),就會(huì)被晉升到老年代中能庆。對(duì)象晉升到老年代的年齡閾值施禾,可以通過(guò)參數(shù) -XX:MaxTenuringThreshold來(lái)設(shè)置。
堆內(nèi)存分配策略

  1. 對(duì)象優(yōu)先在eden區(qū)分配
  2. 大對(duì)象直接進(jìn)入老年代
  3. 長(zhǎng)期存活的對(duì)象進(jìn)入老年代

1.1 對(duì)象優(yōu)先在eden區(qū)分配

目前主流的垃圾收集器都會(huì)采用分代回收算法搁胆,因此需要將堆內(nèi)存分為新生代和老年代弥搞,這樣我們就可以根據(jù)各個(gè)年代的特點(diǎn)選擇合適的垃圾收集算法。

大多數(shù)情況下丰涉,對(duì)象在新生代中 eden 區(qū)分配拓巧。當(dāng) eden 區(qū)沒(méi)有足夠空間進(jìn)行分配時(shí)斯碌,虛擬機(jī)將發(fā)起一次Minor GC.下面我們來(lái)進(jìn)行實(shí)際測(cè)試以下一死。
Minor GC和Full GC 有什么不同呢?

  • 新生代GC(Minor GC):指發(fā)生新生代的的垃圾收集動(dòng)作傻唾,Minor GC非常頻繁投慈,回收速度一般也比較快。
  • 老年代GC(Major GC/Full GC):指發(fā)生在老年代的GC冠骄,出現(xiàn)了Major GC經(jīng)常會(huì)伴隨至少一次的Minor GC(并非絕對(duì))伪煤,Major GC的速度一般會(huì)比Minor GC的慢10倍以上。
    測(cè)試代碼
public class GCTest {
    //jvm 參數(shù)-XX:+PrintGCDetails
    public static void main(String[] args) {
        byte[] allocation1, allocation2;
        allocation1 = new byte[3700*1024*8];
        //allocation2 = new byte[900*1024];
    }
}

運(yùn)行結(jié)果1:

結(jié)果.png

可以看出凛辣,Eden區(qū)已被完全占用抱既,現(xiàn)在我們?cè)贋閍llocation2分配內(nèi)存,打開(kāi)注釋

allocation2 = new byte[900*1024];

運(yùn)行結(jié)果2:

結(jié)果2.png

分配擔(dān)保機(jī)制
因?yàn)榻oallocation2分配內(nèi)存的時(shí)候eden區(qū)內(nèi)存幾乎已經(jīng)被分配完了扁誓,我們剛剛講了當(dāng)Eden區(qū)沒(méi)有足夠空間進(jìn)行分配時(shí)防泵,虛擬機(jī)將發(fā)起一次Minor GC.GC期間虛擬機(jī)又發(fā)現(xiàn)allocation1無(wú)法存入Survivor空間,所以只好通過(guò) 分配擔(dān)保機(jī)制 把新生代的對(duì)象提前轉(zhuǎn)移到老年代中去蝗敢,老年代上的空間足夠存放allocation1捷泞,所以不會(huì)出現(xiàn)Full GC。執(zhí)行Minor GC后寿谴,后面分配的對(duì)象如果能夠存在eden區(qū)的話锁右,還是會(huì)在eden區(qū)分配內(nèi)存。

1.2大對(duì)象直接進(jìn)入老年代

大對(duì)象就是需要大量連續(xù)內(nèi)存空間的對(duì)象(比如:字符串讶泰、數(shù)組)咏瑟。

為什么要這樣呢?
為了避免為大對(duì)象分配內(nèi)存時(shí)由于分配擔(dān)保機(jī)制帶來(lái)的復(fù)制而降低效率痪署。

1.3 長(zhǎng)期存活的對(duì)象將進(jìn)入老年代

既然虛擬機(jī)采用了分代收集的思想來(lái)管理內(nèi)存码泞,那么內(nèi)存回收時(shí)就必須能識(shí)別哪些對(duì)象應(yīng)放在新生代,哪些對(duì)象應(yīng)放在老年代中惠桃。為了做到這一點(diǎn)浦夷,虛擬機(jī)給每個(gè)對(duì)象一個(gè)對(duì)象年齡(Age)計(jì)數(shù)器辖试。

如果對(duì)象在 Eden 出生并經(jīng)過(guò)第一次 Minor GC 后仍然能夠存活,并且能被 Survivor 容納的話劈狐,將被移動(dòng)到 Survivor 空間中罐孝,并將對(duì)象年齡設(shè)為1.對(duì)象在 Survivor 中每熬過(guò)一次 MinorGC,年齡就增加1歲,當(dāng)它的年齡增加到一定程度(默認(rèn)為15歲)肥缔,就會(huì)被晉升到老年代中莲兢。對(duì)象晉升到老年代的年齡閾值,可以通過(guò)參數(shù) -XX:MaxTenuringThreshold 來(lái)設(shè)置续膳。

1.4 動(dòng)態(tài)對(duì)象年齡判定

為了更好的適應(yīng)不同程序的內(nèi)存情況改艇,虛擬機(jī)不是永遠(yuǎn)要求對(duì)象年齡必須達(dá)到了某個(gè)值才能進(jìn)入老年代,如果 Survivor 空間中相同年齡所有對(duì)象大小的總和大于 Survivor 空間的一半坟岔,年齡大于或等于該年齡的對(duì)象就可以直接進(jìn)入老年代谒兄,無(wú)需達(dá)到要求的年齡。

2.對(duì)象已經(jīng)死亡社付?


堆中幾乎放著所有的對(duì)象實(shí)例承疲,對(duì)堆垃圾回收前的第一步就是要判斷那些對(duì)象已經(jīng)死亡(即不能再被任何途徑使用的對(duì)象)。


對(duì)象已經(jīng)死亡分析

2.1引用計(jì)數(shù)法

給對(duì)象中添加一個(gè)引用計(jì)數(shù)器鸥咖,每當(dāng)有一個(gè)地方引用它燕鸽,計(jì)數(shù)器就加1;當(dāng)引用失效啼辣,計(jì)數(shù)器就減1啊研;任何時(shí)候計(jì)數(shù)器為0的對(duì)象就是不可能再被使用的。

這個(gè)方法實(shí)現(xiàn)簡(jiǎn)單鸥拧,效率高党远,但是目前主流的虛擬機(jī)中并沒(méi)有選擇這個(gè)算法來(lái)管理內(nèi)存,其最主要的原因是它很難解決對(duì)象之間相互循環(huán)引用的問(wèn)題住涉。 所謂對(duì)象之間的相互引用問(wèn)題麸锉,如下面代碼所示:除了對(duì)象objA 和 objB 相互引用著對(duì)方之外,這兩個(gè)對(duì)象之間再無(wú)任何引用舆声。但是他們因?yàn)榛ハ嘁脤?duì)方花沉,導(dǎo)致它們的引用計(jì)數(shù)器都不為0,于是引用計(jì)數(shù)算法無(wú)法通知 GC 回收器回收他們媳握。

public class ReferenceCountingGc {
    Object instance = null;
    public static void main(String[] args) {
        ReferenceCountingGc objA = new ReferenceCountingGc();
        ReferenceCountingGc objB = new ReferenceCountingGc();
        objA.instance = objB;
        objB.instance = objA;
        objA = null;
        objB = null;

    }
}

2.2 可達(dá)性分析算法

這個(gè)算法的基本思想就是通過(guò)一系列的稱為 “GC Roots” 的對(duì)象作為起點(diǎn)碱屁,從這些節(jié)點(diǎn)開(kāi)始向下搜索,節(jié)點(diǎn)所走過(guò)的路徑稱為引用鏈蛾找,當(dāng)一個(gè)對(duì)象到 GC Roots 沒(méi)有任何引用鏈相連的話娩脾,則證明此對(duì)象是不可用的。

可達(dá)性分析算法

2.3 再談引用

無(wú)論是通過(guò)引用計(jì)數(shù)法判斷對(duì)象引用數(shù)量打毛,還是通過(guò)可達(dá)性分析法判斷對(duì)象的引用鏈?zhǔn)欠窨蛇_(dá)柿赊,判定對(duì)象的存活都與“引用”有關(guān)俩功。

JDK1.2 之前岁歉,Java 中引用的定義很傳統(tǒng):如果 reference 類(lèi)型的數(shù)據(jù)存儲(chǔ)的數(shù)值代表的是另一塊內(nèi)存的起始地址惠险,就稱這塊內(nèi)存代表一個(gè)引用。

JDK1.2 以后猎塞,Java 對(duì)引用的概念進(jìn)行了擴(kuò)充胰挑,將引用分為強(qiáng)引用蔓罚、軟引用、弱引用瞻颂、虛引用四種(引用強(qiáng)度逐漸減弱)
1. 強(qiáng)引用
以前我們使用的大部分引用實(shí)際上都是強(qiáng)引用豺谈,這是使用最普遍的引用。如果一個(gè)對(duì)象具有強(qiáng)引用贡这,那就類(lèi)似于必不可少的生活用品茬末,垃圾回收器絕不會(huì)回收它。當(dāng)內(nèi)存空 間不足藕坯,Java 虛擬機(jī)寧愿拋出 OutOfMemoryError 錯(cuò)誤团南,使程序異常終止,也不會(huì)靠隨意回收具有強(qiáng)引用的對(duì)象來(lái)解決內(nèi)存不足問(wèn)題炼彪。
2. 軟引用
如果一個(gè)對(duì)象只具有軟引用,那就類(lèi)似于可有可無(wú)的生活用品正歼。如果內(nèi)存空間足夠辐马,垃圾回收器就不會(huì)回收它,如果內(nèi)存空間不足了局义,就會(huì)回收這些對(duì)象的內(nèi)存喜爷。只要垃圾回收器沒(méi)有回收它,該對(duì)象就可以被程序使用萄唇。軟引用可用來(lái)實(shí)現(xiàn)內(nèi)存敏感的高速緩存檩帐。

軟引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果軟引用所引用的對(duì)象被垃圾回收另萤,JAVA 虛擬機(jī)就會(huì)把這個(gè)軟引用加入到與之關(guān)聯(lián)的引用隊(duì)列中湃密。
3. 弱引用
如果一個(gè)對(duì)象只具有弱引用,那就類(lèi)似于可有可無(wú)的生活用品四敞。弱引用與軟引用的區(qū)別在于:只具有弱引用的對(duì)象擁有更短暫的生命周期泛源。在垃圾回收器線程掃描它 所管轄的內(nèi)存區(qū)域的過(guò)程中,一旦發(fā)現(xiàn)了只具有弱引用的對(duì)象忿危,不管當(dāng)前內(nèi)存空間足夠與否达箍,都會(huì)回收它的內(nèi)存。不過(guò)铺厨,由于垃圾回收器是一個(gè)優(yōu)先級(jí)很低的線程缎玫, 因此不一定會(huì)很快發(fā)現(xiàn)那些只具有弱引用的對(duì)象硬纤。

弱引用可以和一個(gè)引用隊(duì)列(ReferenceQueue)聯(lián)合使用,如果弱引用所引用的對(duì)象被垃圾回收赃磨,Java 虛擬機(jī)就會(huì)把這個(gè)弱引用加入到與之關(guān)聯(lián)的引用隊(duì)列中咬摇。
4.虛引用(PhantomReference)
"虛引用"顧名思義,就是形同虛設(shè)煞躬,與其他幾種引用都不同肛鹏,虛引用并不會(huì)決定對(duì)象的生命周期。如果一個(gè)對(duì)象僅持有虛引用恩沛,那么它就和沒(méi)有任何引用一樣在扰,在任何時(shí)候都可能被垃圾回收。

虛引用主要用來(lái)跟蹤對(duì)象被垃圾回收的活動(dòng)雷客。
虛引用與軟引用和弱引用的一個(gè)區(qū)別在于: 虛引用必須和引用隊(duì)列(ReferenceQueue)聯(lián)合使用芒珠。當(dāng)垃 圾回收器準(zhǔn)備回收一個(gè)對(duì)象時(shí),如果發(fā)現(xiàn)它還有虛引用搅裙,就會(huì)在回收對(duì)象的內(nèi)存之前皱卓,把這個(gè)虛引用加入到與之關(guān)聯(lián)的引用隊(duì)列中。程序可以通過(guò)判斷引用隊(duì)列中是 否已經(jīng)加入了虛引用部逮,來(lái)了解被引用的對(duì)象是否將要被垃圾回收娜汁。程序如果發(fā)現(xiàn)某個(gè)虛引用已經(jīng)被加入到引用隊(duì)列,那么就可以在所引用的對(duì)象的內(nèi)存被回收之前采取必要的行動(dòng)兄朋。

特別注意掐禁,在程序設(shè)計(jì)中一般很少使用弱引用與虛引用,使用軟引用的情況較多颅和,這是因?yàn)檐浺每梢约铀?JVM 對(duì)垃圾內(nèi)存的回收速度傅事,可以維護(hù)系統(tǒng)的運(yùn)行安全,防止內(nèi)存溢出(OutOfMemory)等問(wèn)題的產(chǎn)生峡扩。

2.4 不可達(dá)的對(duì)象并非“非死不可”

即使在可達(dá)性分析法中不可達(dá)的對(duì)象蹭越,也并非是“非死不可”的,這時(shí)候它們暫時(shí)處于“緩刑階段”教届,要真正宣告一個(gè)對(duì)象死亡响鹃,至少要經(jīng)歷兩次標(biāo)記過(guò)程;可達(dá)性分析法中不可達(dá)的對(duì)象被第一次標(biāo)記并且進(jìn)行一次篩選巍佑,篩選的條件是此對(duì)象是否有必要執(zhí)行 finalize方法茴迁。當(dāng)對(duì)象沒(méi)有覆蓋 finalize方法,或 finalize方法已經(jīng)被虛擬機(jī)調(diào)用過(guò)時(shí)萤衰,虛擬機(jī)將這兩種情況視為沒(méi)有必要執(zhí)行堕义。

被判定為需要執(zhí)行的對(duì)象將會(huì)被放在一個(gè)隊(duì)列中進(jìn)行第二次標(biāo)記,除非這個(gè)對(duì)象與引用鏈上的任何一個(gè)對(duì)象建立關(guān)聯(lián),否則就會(huì)被真的回收倦卖。

2.5 如何判斷一個(gè)常量是廢棄常量

運(yùn)行時(shí)常量池主要回收的是廢棄的常量洒擦。那么,我們?nèi)绾闻袛嘁粋€(gè)常量是廢棄常量呢怕膛?

假如在常量池中存在字符串 "abc"熟嫩,如果當(dāng)前沒(méi)有任何 String 對(duì)象引用該字符串常量的話,就說(shuō)明常量 "abc" 就是廢棄常量褐捻,如果這時(shí)發(fā)生內(nèi)存回收的話而且有必要的話掸茅,"abc" 就會(huì)被系統(tǒng)清理出常量池。
JDK1.7 及之后版本的 JVM 已經(jīng)將運(yùn)行時(shí)常量池從方法區(qū)中移了出來(lái)柠逞,在 Java 堆(Heap)中開(kāi)辟了一塊區(qū)域存放運(yùn)行時(shí)常量池昧狮。

2.6 如何判斷一個(gè)類(lèi)是無(wú)用的類(lèi)

方法區(qū)主要回收的是無(wú)用的類(lèi),那么如何判斷一個(gè)類(lèi)是無(wú)用的類(lèi)的呢板壮?

判定一個(gè)常量是否是“廢棄常量”比較簡(jiǎn)單逗鸣,而要判定一個(gè)類(lèi)是否是“無(wú)用的類(lèi)”的條件則相對(duì)苛刻許多。類(lèi)需要同時(shí)滿足下面 3 個(gè)條件才能算是 “無(wú)用的類(lèi)” :

  • 該類(lèi)所有的實(shí)例都已經(jīng)被回收绰精,也就是 Java 堆中不存在該類(lèi)的任何實(shí)例撒璧。
  • 加載該類(lèi)的 ClassLoader 已經(jīng)被回收。
  • 該類(lèi)對(duì)應(yīng)的 java.lang.Class 對(duì)象沒(méi)有在任何地方被引用笨使,無(wú)法在任何地方通過(guò)反射訪問(wèn)該類(lèi)的方法卿樱。

虛擬機(jī)可以對(duì)滿足上述 3 個(gè)條件的無(wú)用類(lèi)進(jìn)行回收,這里說(shuō)的僅僅是“可以”阱表,而并不是和對(duì)象一樣不使用了就會(huì)必然被回收殿如。

3.垃圾搜集算法

垃圾搜集算法

3.1 標(biāo)記-清除算法

算法分為“標(biāo)記”和“清除”階段:首先標(biāo)記出所有需要回收的對(duì)象,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象最爬。它是最基礎(chǔ)的收集算法,效率也很高门岔,但是會(huì)帶來(lái)兩個(gè)明顯的問(wèn)題:
1. 效率問(wèn)題
2. 空間問(wèn)題(會(huì)產(chǎn)生大量不連續(xù)的碎片)

標(biāo)記-清除算法

3.2 復(fù)制算法

為了解決效率問(wèn)題爱致,“復(fù)制”收集算法出現(xiàn)了。它可以將內(nèi)存分為大小相同的兩塊寒随,每次使用其中的一塊糠悯。當(dāng)這一塊的內(nèi)存使用完后,就將還存活的對(duì)象復(fù)制到另一塊去妻往,然后再把使用的空間一次清理掉互艾。這樣就使每次的內(nèi)存回收都是對(duì)內(nèi)存區(qū)間的一半進(jìn)行回收。


復(fù)制算法

3.3 標(biāo)記-整理算法

根據(jù)老年代的特點(diǎn)特出的一種標(biāo)記算法讯泣,標(biāo)記過(guò)程仍然與“標(biāo)記-清除”算法一樣纫普,但后續(xù)步驟不是直接對(duì)可回收對(duì)象回收,而是讓所有存活的對(duì)象向一端移動(dòng)好渠,然后直接清理掉端邊界以外的內(nèi)存昨稼。


標(biāo)記-整理算法

3.4 分代收集算法

當(dāng)前虛擬機(jī)的垃圾收集都采用分代收集算法节视,這種算法沒(méi)有什么新的思想,只是根據(jù)對(duì)象存活周期的不同將內(nèi)存分為幾塊假栓。一般將 java 堆分為新生代和老年代寻行,這樣我們就可以根據(jù)各個(gè)年代的特點(diǎn)選擇合適的垃圾收集算法。

比如在新生代中匾荆,每次收集都會(huì)有大量對(duì)象死去拌蜘,所以可以選擇復(fù)制算法,只需要付出少量對(duì)象的復(fù)制成本就可以完成每次垃圾收集牙丽。而老年代的對(duì)象存活幾率是比較高的简卧,而且沒(méi)有額外的空間對(duì)它進(jìn)行分配擔(dān)保,所以我們必須選擇“標(biāo)記-清除”或“標(biāo)記-整理”算法進(jìn)行垃圾收集剩岳。

延伸面試問(wèn)題:HotSpot 為什么要分為新生代和老年代贞滨?

4 垃圾收集器

垃圾收集器

如果說(shuō)收集算法是內(nèi)存回收的方法論,那么垃圾收集器就是內(nèi)存回收的具體實(shí)現(xiàn)拍棕。

雖然我們對(duì)各個(gè)收集器進(jìn)行比較晓铆,但并非要挑選出一個(gè)最好的收集器。因?yàn)橹垃F(xiàn)在為止還沒(méi)有最好的垃圾收集器出現(xiàn)绰播,更加沒(méi)有萬(wàn)能的垃圾收集器骄噪,我們能做的就是根據(jù)具體應(yīng)用場(chǎng)景選擇適合自己的垃圾收集器。試想一下:如果有一種四海之內(nèi)蠢箩、任何場(chǎng)景下都適用的完美收集器存在链蕊,那么我們的 HotSpot 虛擬機(jī)就不會(huì)實(shí)現(xiàn)那么多不同的垃圾收集器了。

4.1 Serial 收集器

Serial(串行)收集器收集器是最基本谬泌、歷史最悠久的垃圾收集器了滔韵。大家看名字就知道這個(gè)收集器是一個(gè)單線程收集器了。它的 “單線程” 的意義不僅僅意味著它只會(huì)使用一條垃圾收集線程去完成垃圾收集工作掌实,更重要的是它在進(jìn)行垃圾收集工作的時(shí)候必須暫停其他所有的工作線程( "Stop The World" )陪蜻,直到它收集結(jié)束。

Serial 收集器

新生代采用復(fù)制算法贱鼻,老年代采用標(biāo)記-整理算法宴卖。
虛擬機(jī)的設(shè)計(jì)者們當(dāng)然知道 Stop The World 帶來(lái)的不良用戶體驗(yàn),所以在后續(xù)的垃圾收集器設(shè)計(jì)中停頓時(shí)間在不斷縮短(仍然還有停頓邻悬,尋找最優(yōu)秀的垃圾收集器的過(guò)程仍然在繼續(xù))症昏。

但是 Serial 收集器有沒(méi)有優(yōu)于其他垃圾收集器的地方呢?當(dāng)然有父丰,它簡(jiǎn)單而高效(與其他收集器的單線程相比)肝谭。Serial 收集器由于沒(méi)有線程交互的開(kāi)銷(xiāo),自然可以獲得很高的單線程收集效率。Serial 收集器對(duì)于運(yùn)行在 **Client **模式下的虛擬機(jī)來(lái)說(shuō)是個(gè)不錯(cuò)的選擇分苇。

4.2 ParNew 收集器

ParNew 收集器其實(shí)就是 Serial 收集器的多線程版本添诉,除了使用多線程進(jìn)行垃圾收集外,其余行為(控制參數(shù)医寿、收集算法栏赴、回收策略等等)和 Serial 收集器完全一樣。
新生代采用復(fù)制算法靖秩,老年代采用標(biāo)記-整理算法须眷。

ParNew 收集器

它是許多運(yùn)行在 **Server **模式下的虛擬機(jī)的首要選擇,除了 Serial 收集器外沟突,只有它能與 CMS 收集器(真正意義上的并發(fā)收集器花颗,后面會(huì)介紹到)配合工作。

4.3 Parallel Scavenge 收集器

Parallel Scavenge 收集器類(lèi)似于 ParNew 收集器惠拭。 那么它有什么特別之處呢扩劝?

-XX:+UseParallelGC
使用 Parallel 收集器+ 老年代串行
-XX:+UseParallelOldGC
使用 Parallel 收集器+ 老年代并行
Parallel Scavenge 收集器關(guān)注點(diǎn)是吞吐量(高效率的利用 CPU)。CMS 等垃圾收集器的關(guān)注點(diǎn)更多的是用戶線程的停頓時(shí)間(提高用戶體驗(yàn))职辅。**所謂吞吐量就是 CPU 中用于運(yùn)行用戶代碼的時(shí)間與 CPU 總消耗時(shí)間的比值棒呛。 **Parallel Scavenge 收集器提供了很多參數(shù)供用戶找到最合適的停頓時(shí)間或最大吞吐量,如果對(duì)于收集器運(yùn)作不太了解的話域携,手工優(yōu)化存在的話可以選擇把內(nèi)存管理優(yōu)化交給虛擬機(jī)去完成也是一個(gè)不錯(cuò)的選擇簇秒。

新生代采用復(fù)制算法,老年代采用標(biāo)記-整理算法秀鞭。


Parallel Scavenge

4.4.Serial Old 收集器

Serial 收集器的老年代版本趋观,它同樣是一個(gè)單線程收集器。它主要有兩大用途:一種用途是在 JDK1.5 以及以前的版本中與 Parallel Scavenge 收集器搭配使用锋边,另一種用途是作為 CMS 收集器的后備方案皱坛。

4.5 Parallel Old 收集器

Parallel Scavenge 收集器的老年代版本。使用多線程和“標(biāo)記-整理”算法豆巨。在注重吞吐量以及 CPU 資源的場(chǎng)合麸恍,都可以優(yōu)先考慮 Parallel Scavenge 收集器和 Parallel Old 收集器。

4.6 CMS 收集器

CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時(shí)間為目標(biāo)的收集器搀矫。它而非常符合在注重用戶體驗(yàn)的應(yīng)用上使用。

CMS(Concurrent Mark Sweep)收集器是 HotSpot 虛擬機(jī)第一款真正意義上的并發(fā)收集器刻肄,它第一次實(shí)現(xiàn)了讓垃圾收集線程與用戶線程(基本上)同時(shí)工作瓤球。

從名字中的Mark Sweep這兩個(gè)詞可以看出,CMS 收集器是一種 “標(biāo)記-清除”算法實(shí)現(xiàn)的敏弃,它的運(yùn)作過(guò)程相比于前面幾種垃圾收集器來(lái)說(shuō)更加復(fù)雜一些卦羡。整個(gè)過(guò)程分為四個(gè)步驟:

  • 初始標(biāo)記: 暫停所有的其他線程,并記錄下直接與 root 相連的對(duì)象,速度很快 绿饵;
  • 并發(fā)標(biāo)記: 同時(shí)開(kāi)啟 GC 和用戶線程欠肾,用一個(gè)閉包結(jié)構(gòu)去記錄可達(dá)對(duì)象。但在這個(gè)階段結(jié)束拟赊,這個(gè)閉包結(jié)構(gòu)并不能保證包含當(dāng)前所有的可達(dá)對(duì)象刺桃。因?yàn)橛脩艟€程可能會(huì)不斷的更新引用域,所以 GC 線程無(wú)法保證可達(dá)性分析的實(shí)時(shí)性吸祟。所以這個(gè)算法里會(huì)跟蹤記錄這些發(fā)生引用更新的地方瑟慈。
  • 重新標(biāo)記: 重新標(biāo)記階段就是為了修正并發(fā)標(biāo)記期間因?yàn)橛脩舫绦蚶^續(xù)運(yùn)行而導(dǎo)致標(biāo)記產(chǎn)生變動(dòng)的那一部分對(duì)象的標(biāo)記記錄,這個(gè)階段的停頓時(shí)間一般會(huì)比初始標(biāo)記階段的時(shí)間稍長(zhǎng)屋匕,遠(yuǎn)遠(yuǎn)比并發(fā)標(biāo)記階段時(shí)間短
  • 并發(fā)清除: 開(kāi)啟用戶線程葛碧,同時(shí) GC 線程開(kāi)始對(duì)為標(biāo)記的區(qū)域做清掃。
    cms

    從它的名字就可以看出它是一款優(yōu)秀的垃圾收集器过吻,主要優(yōu)點(diǎn):并發(fā)收集进泼、低停頓。但是它有下面三個(gè)明顯的缺點(diǎn):
  • 對(duì)CPU資源敏感
  • 無(wú)法清除浮動(dòng)垃圾
  • 清理結(jié)束后會(huì)產(chǎn)生大量碎片

4.7 G1收集器

G1 (Garbage-First) 是一款面向服務(wù)器的垃圾收集器,主要針對(duì)配備多顆處理器及大容量?jī)?nèi)存的機(jī)器. 以極高概率滿足 GC 停頓時(shí)間要求的同時(shí),還具備高吞吐量性能特征.

被視為 JDK1.7 中 HotSpot 虛擬機(jī)的一個(gè)重要進(jìn)化特征纤虽。它具備一下特點(diǎn):

  • 并行與并發(fā):G1 能充分利用 CPU乳绕、多核環(huán)境下的硬件優(yōu)勢(shì),使用多個(gè) CPU(CPU 或者 CPU 核心)來(lái)縮短 Stop-The-World 停頓時(shí)間廓推。部分其他收集器原本需要停頓 Java 線程執(zhí)行的 GC 動(dòng)作刷袍,G1 收集器仍然可以通過(guò)并發(fā)的方式讓 java 程序繼續(xù)執(zhí)行。
  • 分代收集:雖然 G1 可以不需要其他收集器配合就能獨(dú)立管理整個(gè) GC 堆樊展,但是還是保留了分代的概念呻纹。
  • 空間整合:與 CMS 的“標(biāo)記--清理”算法不同,G1 從整體來(lái)看是基于“標(biāo)記整理”算法實(shí)現(xiàn)的收集器专缠;從局部上來(lái)看是基于“復(fù)制”算法實(shí)現(xiàn)的雷酪。
  • 可預(yù)測(cè)的停頓:這是 G1 相對(duì)于 CMS 的另一個(gè)大優(yōu)勢(shì),降低停頓時(shí)間是 G1 和 CMS 共同的關(guān)注點(diǎn)涝婉,但 G1 除了追求低停頓外哥力,還能建立可預(yù)測(cè)的停頓時(shí)間模型,能讓使用者明確指定在一個(gè)長(zhǎng)度為 M 毫秒的時(shí)間片段內(nèi)墩弯。

G1 收集器的運(yùn)作大致分為以下幾個(gè)步驟:

  1. 初始標(biāo)記
  2. 并發(fā)標(biāo)記
  3. 最終標(biāo)記
  4. 篩選回收

G1 收集器在后臺(tái)維護(hù)了一個(gè)優(yōu)先列表吩跋,每次根據(jù)允許的收集時(shí)間,優(yōu)先選擇回收價(jià)值最大的 Region(這也就是它的名字 Garbage-First 的由來(lái))渔工。這種使用 Region 劃分內(nèi)存空間以及有優(yōu)先級(jí)的區(qū)域回收方式锌钮,保證了 GF 收集器在有限時(shí)間內(nèi)可以盡可能高的收集效率(把內(nèi)存化整為零)。

搬運(yùn)

javaGuide

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末引矩,一起剝皮案震驚了整個(gè)濱河市梁丘,隨后出現(xiàn)的幾起案子侵浸,更是在濱河造成了極大的恐慌,老刑警劉巖氛谜,帶你破解...
    沈念sama閱讀 217,826評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掏觉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡值漫,警方通過(guò)查閱死者的電腦和手機(jī)澳腹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)惭嚣,“玉大人遵湖,你說(shuō)我怎么就攤上這事⊥硗蹋” “怎么了延旧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,234評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)槽地。 經(jīng)常有香客問(wèn)我迁沫,道長(zhǎng),這世上最難降的妖魔是什么捌蚊? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,562評(píng)論 1 293
  • 正文 為了忘掉前任集畅,我火速辦了婚禮,結(jié)果婚禮上缅糟,老公的妹妹穿的比我還像新娘挺智。我一直安慰自己,他們只是感情好窗宦,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,611評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布赦颇。 她就那樣靜靜地躺著,像睡著了一般赴涵。 火紅的嫁衣襯著肌膚如雪媒怯。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,482評(píng)論 1 302
  • 那天髓窜,我揣著相機(jī)與錄音扇苞,去河邊找鬼。 笑死寄纵,一個(gè)胖子當(dāng)著我的面吹牛鳖敷,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播程拭,決...
    沈念sama閱讀 40,271評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼哄陶,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了哺壶?” 一聲冷哼從身側(cè)響起屋吨,我...
    開(kāi)封第一講書(shū)人閱讀 39,166評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎山宾,沒(méi)想到半個(gè)月后至扰,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,608評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡资锰,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,814評(píng)論 3 336
  • 正文 我和宋清朗相戀三年敢课,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绷杜。...
    茶點(diǎn)故事閱讀 39,926評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡直秆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鞭盟,到底是詐尸還是另有隱情圾结,我是刑警寧澤,帶...
    沈念sama閱讀 35,644評(píng)論 5 346
  • 正文 年R本政府宣布齿诉,位于F島的核電站筝野,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏粤剧。R本人自食惡果不足惜歇竟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,249評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抵恋。 院中可真熱鬧焕议,春花似錦、人聲如沸弧关。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,866評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)梯醒。三九已至宽堆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間茸习,已是汗流浹背畜隶。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,991評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留号胚,地道東北人籽慢。 一個(gè)月前我還...
    沈念sama閱讀 48,063評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像猫胁,于是被迫代替她去往敵國(guó)和親箱亿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,871評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 垃圾收集基礎(chǔ) Java 語(yǔ)言的一大特點(diǎn)就是可以進(jìn)行自動(dòng)垃圾回收處理弃秆,而無(wú)需開(kāi)發(fā)人員過(guò)于關(guān)注系統(tǒng)資源届惋,例如內(nèi)存資源的...
    Austin_Brant閱讀 745評(píng)論 0 2
  • 本節(jié)常見(jiàn)面試題: 問(wèn)題答案在文中都有提到 如何判斷對(duì)象是否死亡(兩種方法)髓帽。 簡(jiǎn)單的介紹一下強(qiáng)引用、軟引用脑豹、弱引用...
    Java黎先生閱讀 257評(píng)論 0 4
  • 寫(xiě)在前面 本節(jié)常見(jiàn)面試題: 問(wèn)題答案在文中都有提到 如何判斷對(duì)象是否死亡(兩種方法)郑藏。 簡(jiǎn)單的介紹一下強(qiáng)引用、軟引...
    哈哈大圣閱讀 216評(píng)論 0 1
  • 哪些內(nèi)存需要回收瘩欺?哪些內(nèi)存需要回收是垃圾回收機(jī)制第一個(gè)要考慮的問(wèn)題必盖,所謂“要回收的垃圾”無(wú)非就是那些不可能再被任何...
    Winterfell_Z閱讀 336評(píng)論 0 1
  • 這篇文章可能會(huì)是一篇內(nèi)容非掣柚啵枯燥的文章,因?yàn)樗挥幸粋€(gè)主題詞:安全拍埠。也許您已經(jīng)在其他的網(wǎng)站讀過(guò)無(wú)數(shù)篇類(lèi)似內(nèi)容的文章...
    LyndonCA閱讀 500評(píng)論 0 0