HotSpot垃圾回收算法概述

引言

在內(nèi)存管理中,垃圾是指那些不再被使用的對(duì)象。對(duì)于一個(gè)垃圾回收器(Garbage Collector)髓抑,它需要完成三件事:

  1. 分配內(nèi)存:垃圾回收算法的設(shè)計(jì)往往制約了內(nèi)存分配的方式飞蚓;
  2. 確保存活對(duì)象不會(huì)被回收
  3. 回收垃圾對(duì)象

很顯然的是,一個(gè)垃圾回收器并不提供回收全部垃圾對(duì)象的保證曲饱。這意味著一次垃圾回收結(jié)束之后,內(nèi)存中依然可能存活著不會(huì)再被使用的對(duì)象珠月。

對(duì)于HotSpot中的垃圾回收算法而言扩淀,其設(shè)計(jì)都是建立在兩個(gè)經(jīng)驗(yàn)法則之上的:

  1. 對(duì)于大部分對(duì)象來(lái)說(shuō),它會(huì)在“年輕”的時(shí)候死去啤挎;
  2. 很少引用存在于“年老的”和“年輕的”對(duì)象之間驻谆;

這里使用的“年輕的”和“年老的”的兩種說(shuō)法,是指存活時(shí)間的長(zhǎng)短庆聘。這兩條的經(jīng)驗(yàn)法則表明胜臊,大部分的對(duì)象存活時(shí)間都很短,無(wú)法活過(guò)一個(gè)回收周期伙判。并且象对,存活時(shí)間長(zhǎng)的對(duì)象傾向于引用存活時(shí)間長(zhǎng)的對(duì)象,而存活時(shí)間短的對(duì)象傾向于引用存活時(shí)間短的對(duì)象宴抚。對(duì)于大部分的應(yīng)用來(lái)說(shuō)勒魔,這兩個(gè)經(jīng)驗(yàn)法則都是適用的。

設(shè)計(jì)因素

在垃圾算法回收的設(shè)計(jì)中菇曲,需要考慮的因素有:

  1. 串行(Serial)和并行(Parallel)
  2. 并發(fā)(Concurrent)和暫停式(Stop the world)
  3. 壓縮(Compacting)和非壓縮(Non-Compacting):這一組概念是指冠绢,在垃圾回收結(jié)束之后,是否需要把所有的存活對(duì)象挪到一起常潮,占據(jù)一個(gè)連續(xù)空間弟胀。在Compacting之后,也意味著可用內(nèi)存占據(jù)了一個(gè)連續(xù)的空間,這個(gè)時(shí)候就可以使用bump-the-pointer的分配內(nèi)存技術(shù)邮利。在這種技術(shù)中弥雹,只需要持有一個(gè)指針指向已分配內(nèi)存的尾部。每次分配的時(shí)候只需要檢查剩余空閑空間能否容納新的對(duì)象延届,而后分配內(nèi)存并且將指針指向新的尾部剪勿。這種Compacting的計(jì)數(shù),在一些算法中需要付出額外的代價(jià)方庭,這個(gè)代價(jià)要么是需要額外的內(nèi)存空間厕吉,要么是額外的回收時(shí)間。

并發(fā)和并行是一對(duì)比較容易搞混的概念械念。并發(fā)是指头朱,垃圾回收和應(yīng)用可以在一段時(shí)間內(nèi)同時(shí)運(yùn)行,這個(gè)概念和操作系統(tǒng)上的概念是一致的龄减。在HotSpot中项钮,并發(fā)垃圾回收算法中大部分垃圾回收的工作都是在并發(fā)的情況下完成的,但是并不能完全免除Stop-the-world希停。并行是指利用多個(gè)CPU烁巫,多個(gè)線程同時(shí)進(jìn)行垃圾回收。

度量

在衡量一個(gè)垃圾回收算法上宠能,最為主要的兩個(gè)度量是:

  1. 暫停時(shí)間(pause time):是指在一次垃圾回收中亚隙,Stop-the-world狀態(tài)下占用的時(shí)間。暫停時(shí)間主要受到算法和堆大小的影響违崇。相同條件下藻糖,堆越小潜索,暫停時(shí)間就越短题诵。但是堆越小梢睛,那么回收頻率就越高。
  2. 吞吐量(throughput):一般而言肴楷,堆越大水由,吞吐量越高荠呐,回收頻率越低赛蔫。

可以看到一個(gè)有趣的地方:暫停時(shí)間和吞吐量對(duì)堆的大小要求是不一樣的。暫停時(shí)間要想短泥张,那么應(yīng)該有更小堆呵恢;而吞吐量要大,需要更大的堆媚创。

分代

前面提到渗钉,大部分的對(duì)象都會(huì)在年輕的時(shí)候死去。因此將那些年輕對(duì)象放在一起,將那些年老的對(duì)象放在一起鳄橘,在垃圾回收的時(shí)候區(qū)別對(duì)待声离,就是很有價(jià)值的。這就是分代(generation)的想法瘫怜。在HotSpot中术徊,所有的垃圾回收算法都是分代垃圾回收算法。年輕代垃圾回收更加頻繁鲸湃,并且在一次回收中能夠存活下來(lái)的對(duì)象也是及其稀少的赠涮。在年輕代存活過(guò)一段時(shí)間(通常是活過(guò)了幾次年輕代的垃圾回收周期)后,對(duì)象會(huì)被提升(promoted or tenured)到老年代暗挑。如圖:

分代

注:圖片引自Memory Managerment in the Java HotSpot Virtual Machine

除此以外笋除,大對(duì)象也會(huì)直接分配在老年代≌桑總體來(lái)說(shuō)垃它,老年代的對(duì)象存活時(shí)間更長(zhǎng),并且老年代分配出去的空間增長(zhǎng)緩慢烹看,由此導(dǎo)致了老年代垃圾回收不頻繁嗤瞎。

這種提升策略會(huì)有一個(gè)問(wèn)題,就是老年代可能并沒(méi)有足夠的空間容納這些從年輕代提升上來(lái)的對(duì)象听系。在這種情況下贝奇,會(huì)觸發(fā)一次老年代的垃圾回收。在極端的情況下靠胜,整個(gè)年輕代的所有對(duì)象都會(huì)被提升到老年代掉瞳。因此,老年代比年輕代要大是順理成章的事情浪漠。

關(guān)于老年代什么時(shí)候檢測(cè)剩余空閑空間陕习,判斷能否容納被提升的對(duì)象,我閱讀的文檔文章中并沒(méi)有明確提出址愿。它可能發(fā)生在每提升一個(gè)對(duì)象该镣,就執(zhí)行一次檢測(cè);也可能是在年輕代回收之前响谓,根據(jù)有多少待提升對(duì)象進(jìn)行一次檢測(cè)损合;最后一種可能是,檢測(cè)發(fā)生在年輕代垃圾回收之前——也就是意味著每次檢測(cè)都是拿年輕代的大小和老年代空閑空間的大小進(jìn)行比較娘纷。在Tuning Garbaga Collection with the 5.0 Java Virtual Machine中有一段話嫁审,“But for applications needing the largest possible heap, an eden bigger than half the virtually committed size of the heap is useless: only major collections would occur”。從這句話來(lái)看赖晶,老年代似乎并不管究竟有多少需要提升律适,也不管會(huì)回收多少垃圾,每一次比較都是用空閑空間和整個(gè)年輕代的大小進(jìn)行比較。

在HotSpot中的分代為:

  1. 年輕代(young generation)分成Eden和Survivor捂贿。(注:在一些特殊的平臺(tái)上纠修,HotSpot并沒(méi)有Eden和Survivor的概念)
    1. Eden:年輕代只有一個(gè)Eden。對(duì)象分配都是直接分配在Eden中的厂僧;
    2. Survivor:年輕代中會(huì)有兩個(gè)Survivor分瘾,拿來(lái)存放在一次垃圾回收算法中存活的對(duì)象。每次算法運(yùn)行的時(shí)候吁系,會(huì)把Eden和一個(gè)Survivor(標(biāo)記為from)中的存活對(duì)象復(fù)制到另外一個(gè)Survivor(標(biāo)記為to)中德召;
  2. 老年代(old generation):
  3. 持久代(perm generation):持久代幾乎不會(huì)出現(xiàn)垃圾回收(有些應(yīng)用或者有些平臺(tái)會(huì)有這種需求),本文將不會(huì)涉及這個(gè)地方汽纤;

在HotSpot中上岗,Eden和Survivor的比例可以通過(guò)使用++NewRatio來(lái)

Serial Collector

原理

Serial Collector(串行回收器)在年輕代是一個(gè)使用標(biāo)記-復(fù)制算法的回收器。標(biāo)記-復(fù)制垃圾回收算法可以分成兩個(gè)階段:

  1. 標(biāo)記階段:從根(root)出發(fā)蕴坪,沿著引用鏈標(biāo)記存活對(duì)象肴掷;
  2. 復(fù)制:將存活對(duì)象復(fù)制到特定的區(qū)域;
    如圖:
Serial GC

GC完成之后:

After Serial GC

注:圖片引自Memory Managerment in the Java HotSpot Virtual Machine

在標(biāo)記階段背传,Serial Collector將Eden中和這次被標(biāo)記為from(恰好是上次標(biāo)記為to)的Survivor中的存活對(duì)象標(biāo)記出來(lái)呆瞻,而后將存活對(duì)象復(fù)制到另外一個(gè)Survivor中。在這個(gè)過(guò)程中径玖,可能有部分對(duì)象的存活時(shí)間達(dá)到了提升到老年代的標(biāo)準(zhǔn)痴脾,因此會(huì)有一些對(duì)象被復(fù)制到老年代。

Serial Collector也可以被應(yīng)用在老年代梳星,所不同的是赞赖,老年代并沒(méi)有什么Eden和Survivor的劃分。在老年代使用的是標(biāo)記-清掃-整理算法冤灾。該算法流程為:

  1. 標(biāo)記:比較存活的對(duì)象
  2. 清掃:在該階段前域,會(huì)識(shí)別出垃圾對(duì)象≡隙郑“清掃”這個(gè)概念帶有一些誤導(dǎo)的色彩匿垄,在算法的實(shí)現(xiàn)中,并不需要真的對(duì)垃圾對(duì)象占據(jù)的內(nèi)存進(jìn)行清掃归粉,僅僅標(biāo)記一下就夠了椿疗。(注:在新對(duì)象被分配到該被清掃的區(qū)域的時(shí)候,會(huì)執(zhí)行一次JVM層面上的初始化過(guò)程盏浇,該過(guò)程會(huì)把該內(nèi)存區(qū)域重置变丧,因而有了Java語(yǔ)言中的不同數(shù)據(jù)類型的默認(rèn)值一說(shuō))
  3. 整理:將所有的存活對(duì)象都挪到一端

可以看到的是,在使用Serial Collector的情況下绢掰,無(wú)論是老年代還是年輕代,其內(nèi)存都經(jīng)過(guò)了Compacting,所有的存活對(duì)象占據(jù)了一塊連續(xù)的空間滴劲,而空閑空間也是占據(jù)了一個(gè)連續(xù)的空間攻晒。因此在分配內(nèi)存空間的時(shí)候都可以使用bump-the-pointer的技術(shù)。

使用場(chǎng)景

Serial Collector主要適用于對(duì)pause time要求不高班挖,可用內(nèi)存和CPU數(shù)量都比較小的應(yīng)用上鲁捏。在新的HotSpot中,如果虛擬機(jī)運(yùn)行的平臺(tái)是client-style類型的萧芙,那么就會(huì)采用Serial Collector给梅。

影響因素和JVM選項(xiàng)

Serial Collector的性能和幾個(gè)因素有關(guān):

  1. 堆大小。如前面所言双揪,堆的大小直接影響了吞吐量和停頓時(shí)間(pause time)
  2. NewRatio:這個(gè)因素調(diào)節(jié)的是年輕代和老年代的比例动羽。比如說(shuō)值是3,那么意味著年輕代和老年代的比例是1:3渔期。對(duì)于Serial Collector來(lái)說(shuō)运吓,年輕代過(guò)大,會(huì)造成相應(yīng)老年代過(guò)小疯趟,這會(huì)導(dǎo)致更加頻繁地觸發(fā)老年代的垃圾回收(也即是major GC)拘哨。而如果年輕代過(guò)小,那么年輕代就會(huì)更加頻繁GC信峻,并且相對(duì)而言倦青,更加多的大對(duì)象會(huì)被直接分配到老年代。在這種情況下盹舞,觸發(fā)老年代GC的頻率要降低姨夹,但是pause time就要提升;
  3. SurvivorRatio:該選項(xiàng)調(diào)節(jié)的是年輕代中Suvivor部分占據(jù)的大小矾策。舉例來(lái)說(shuō)磷账,如果值是8,那么意味著贾虽,每個(gè)Survivor占據(jù)的大小是1/(8+2)逃糟。Survivor的大小是比較關(guān)鍵的。如果Survivor比較小蓬豁,那么Survivor很容易就裝不下存活對(duì)象绰咽,因此有更加多的存活對(duì)象被逼提升到老年代。這會(huì)帶來(lái)兩個(gè)影響:一個(gè)是老年代更加快裝滿地粪,另外一個(gè)是老年代指向年輕代的引用會(huì)增加——這個(gè)因素會(huì)影響mark階段根的大小取募。而如果Survivor過(guò)大,那么每次裝完存活對(duì)象之后還會(huì)剩下一段沒(méi)有利用的空間蟆技,這段空間就會(huì)被浪費(fèi)玩敏,影響年輕代的GC頻率和吞吐量斗忌;

還有其余的一些選項(xiàng),如NewSize和MaxNewSize等旺聚,讀者可以自己去找相關(guān)的資料閱讀织阳。

Parallel Collector

原理

Parallel Collector(并行垃圾回收器)和Serial Collector(串行回收器)比起來(lái),要復(fù)雜微妙很多砰粹∵蠖悖總體的算法思想是一致的,不過(guò)Serial Collector在任何階段都是單線程在運(yùn)行的碱璃,而Parallel Collector則是多線程運(yùn)行的弄痹。額外要注意的是,即便在虛擬機(jī)中指定了Parallel Collector嵌器,但是老年代的回收肛真,也就是major collection還是使用和Serail Collector一樣的單線程!換句話來(lái)說(shuō)嘴秸,只有對(duì)年輕代的回收(minor collection)將會(huì)采用多線程毁欣。如圖:

Parallel GC

注:圖片來(lái)自Memory Managerment in the Java HotSpot Virtual Machine。

Parallel Collector與Serial Collector比起來(lái)岳掐,以下這些方面是要注意的:

  1. 工作分配凭疮。這是一個(gè)算法設(shè)計(jì)的難點(diǎn)。舉例來(lái)說(shuō)串述,我們可以將整個(gè)標(biāo)記階段看成是一個(gè)大的任務(wù)执解,由一系列的小的工作組成,那么在多線程的情況下纲酗,要考慮哪個(gè)線程負(fù)責(zé)標(biāo)記哪一塊衰腌,還要考慮負(fù)載均衡——即任務(wù)的分配要公平,不能一些線程很快完成任務(wù)停下來(lái)觅赊,等待其余線程完成自己的工作右蕊;

在標(biāo)記階段,還有一個(gè)很有意思的話題吮螺。就是如果多線程在進(jìn)行標(biāo)記的時(shí)候饶囚,可能會(huì)重復(fù)標(biāo)記一個(gè)對(duì)象為存活對(duì)象,這并不會(huì)影響算法的正確性鸠补,只是會(huì)影響算法的性能萝风。關(guān)于并行回收算法的更加細(xì)致的描述可以閱讀《垃圾回收算法手冊(cè)——自動(dòng)內(nèi)存管理的藝術(shù)》第14章。

  1. 在多線程的情況下紫岩,提升對(duì)象到老年代會(huì)遇到新的問(wèn)題规惰。按照原來(lái)的bump-the-point的算法,每一次分配都是指針的遞增泉蝌。假設(shè)說(shuō)現(xiàn)在有兩個(gè)線程同時(shí)在老年代分配空間歇万,分配前的指針指向100揩晴,其中一個(gè)線程將指針增加到150,而另外一個(gè)線程將指針設(shè)置為200.那么最終的結(jié)果就可能是150堕花,也可能是200文狱。一種自然的想法是加鎖粥鞋,但是和一般應(yīng)用里面鎖爭(zhēng)用會(huì)帶來(lái)?yè)p耗一般缘挽,這也會(huì)導(dǎo)致老年代的分配損耗增加(這會(huì)極大影響pause time和吞吐量)。而Paraller Collector采用了另外一種被稱為T(mén)LABs(thread-local allocation buffers)技術(shù):它將老年代劃分成一個(gè)個(gè)固定大小的Buffer呻粹,給每一個(gè)回收線程分配一個(gè)壕曼,回收線程就只在自己的Buffer內(nèi)分配空間。在這種情況下等浊,只有線程重新申請(qǐng)一個(gè)Buffer的時(shí)候腮郊,才會(huì)引入并發(fā)的問(wèn)題。但是這會(huì)帶來(lái)另外一個(gè)問(wèn)題筹燕,就是每一個(gè)線程并不能恰好用完一個(gè)Buffer轧飞,可能出現(xiàn)的情況是,一個(gè)線程檢測(cè)到Buffer里面的空閑空間已經(jīng)不夠了撒踪,于是只能申請(qǐng)另外一個(gè)Buffer过咬。而原來(lái)的Buffer的那部分不足的空間就會(huì)被浪費(fèi)掉。這就是所謂的float garbage制妄。

還有一個(gè)誤解要澄清掸绞。應(yīng)用有多少個(gè)線程在運(yùn)行并不決定有多少個(gè)線程回收。舉例說(shuō)一個(gè)應(yīng)用有200個(gè)線程正在運(yùn)行耕捞,但是在垃圾回收的時(shí)候衔掸,回收的線程可能只有10個(gè)。

Parallel Collector有一個(gè)變種叫做Parallel Compacting Collector俺抽。從名字上很令人困惑敞映,因?yàn)閺那懊鎸?duì)Serial Collector上的敘述中可以看出來(lái),major collection使用的算法磷斧,本身就是compacting的振愿。我簡(jiǎn)單描述一下兩者的區(qū)別:對(duì)于Parallel Collector來(lái)說(shuō),每一次回收都會(huì)Compacting整個(gè)老年代瞳抓;而對(duì)于Parallel Compacting Collector來(lái)說(shuō)并不是埃疫。它會(huì)檢測(cè)一個(gè)區(qū)域的存活對(duì)象的密度,來(lái)決定是否進(jìn)行compacting孩哑。更多相關(guān)信息可以閱讀《Memory Managerment in the Java HotSpot Virtual Machine》和《垃圾回收算法手冊(cè)——自動(dòng)內(nèi)存管理的藝術(shù)》栓霜。

使用場(chǎng)景

Parallel Collector又被叫做Throughput Collector。所以很顯然横蜒,它適用于要求吞吐量高的場(chǎng)景胳蛮。

影響因素和JVM選項(xiàng)

前面在Serial Collector中談及的影響因素销凑,對(duì)Parallel Collector同樣是適用的,而且還額外收到以下這些因素的影響:

  1. GC線程數(shù)量:線程數(shù)量和float garbage的數(shù)量是成正相關(guān)關(guān)系仅炊;
  2. Buffer大小
  3. CPU數(shù)量:在單個(gè)CPU的情況下斗幼,Parallel Collector的表現(xiàn)不如Serial Collector;在兩個(gè)CPU的情況下抚垄,Parallel Collector可以達(dá)到和Serial Collector相當(dāng)?shù)谋憩F(xiàn)蜕窿,甚至?xí)^(guò)一點(diǎn)。在CPU超過(guò)兩個(gè)的情況下呆馁, 表現(xiàn)都會(huì)比Serial Collector好桐经。但是并不是CPU越多性能越好。在當(dāng)前算法的實(shí)現(xiàn)中浙滤,CPU數(shù)量超過(guò)32(16阴挣?有點(diǎn)忘記了,閱讀的資料也忘了是哪個(gè)了)性能反而會(huì)下降纺腊;

CMS Collector

原理

CMS Collector(Concurrent Mark-Sweep Collector)畔咧,是一個(gè)并發(fā)垃圾回收器,這意味著在垃圾回收的過(guò)程中間揖膜,大部分時(shí)間里誓沸,應(yīng)用還是可以繼續(xù)運(yùn)行的。所以次氨,這里所謂的并發(fā)蔽介,更加多的是指應(yīng)用和垃圾回收的并發(fā)。同時(shí)CMS Collector也是多線程的煮寡,也即它也是Parallel(并行)的虹蓄。

在CMS Collector里,年輕代的回收是和Parallel Collector一樣的幸撕,也就是說(shuō)薇组,年輕代的回收是stop-the-world式的。只有在老年代坐儿,相應(yīng)的major collection里面才會(huì)使用CMS算法律胀。
CMS的過(guò)程如圖:

CMS

注:圖片來(lái)自Memory Managerment in the Java HotSpot Virtual Machine

  1. initial mark:initial mark是stop-the-world式的,也就是說(shuō)在這個(gè)階段是需要暫停應(yīng)用的執(zhí)行貌矿。initial mark只是識(shí)別出來(lái)標(biāo)記的根(準(zhǔn)確說(shuō)法是"identifies the initial set of live objects directly reachable from application code"炭菌,另外在StackOverFlow上看到一段話"This includes: Reference from thread stacks, Reference from young space.")
  2. concurrent mark:并發(fā)標(biāo)記階段。在該階段逛漫,應(yīng)用可以繼續(xù)運(yùn)行黑低;
  3. remark:在concurrent mark階段,因?yàn)閼?yīng)用依舊在運(yùn)行,所以可能原本標(biāo)記為垃圾的對(duì)象又“復(fù)活”了克握,也可能分配了新的對(duì)象蕾管。所以會(huì)引入找一個(gè)remark階段。該階段也是stop-the-world的菩暗;
  4. concurrent sweep:并發(fā)清掃掰曾。該階段應(yīng)用會(huì)繼續(xù)運(yùn)行;

因?yàn)橐雰蓚€(gè)并發(fā)階段停团,所以會(huì)造成很多問(wèn)題:

  1. 如何快速的remark旷坦?顯然,如果要是在remark中還是需要掃描對(duì)象客蹋,那么該Collector就沒(méi)多大必要存在了塞蹭。CMS Collector采用了一種稱為“card table”的技術(shù)孽江。card table簡(jiǎn)單理解是并發(fā)回收器的工作列表讶坯。CMS使用該技術(shù)會(huì)在concurrent mark階段,將改變了引用關(guān)系的對(duì)象標(biāo)記為“dirty”岗屏,在remark階段中重新掃描辆琅;
  2. 還有一個(gè)問(wèn)題是,在concurrent mark階段这刷,可能觸發(fā)minor collection婉烟。CMS Collector會(huì)采用一種稱為Mod Union Table的技術(shù)來(lái)記錄GC前后card的信息。所以綜合這兩種情況暇屋,CMS Collector在remark階段會(huì)從Mod Union Table和Card Table出發(fā)似袁;
  3. 因?yàn)樵诨厥针A段還有可能分配對(duì)象,所以垃圾回收不能等內(nèi)存滿了才開(kāi)始咐刨,必須要提前開(kāi)始昙衅。但是CMS Collector并不提供在回收階段一定含有足夠的空閑給應(yīng)用分配對(duì)象。這就會(huì)造成一個(gè)問(wèn)題定鸟,就是在垃圾回收階段而涉,空閑空間不足了。這個(gè)時(shí)候联予,應(yīng)用會(huì)被停下來(lái)啼县,也就是進(jìn)入到stop-the-world狀態(tài),直到回收完成沸久;
  4. 該回收的垃圾沒(méi)有被回收季眷。這也被稱為floating garbage。這主要是出現(xiàn)在卷胯,原本一個(gè)對(duì)象被標(biāo)記為存活子刮,但是在concurrent階段,應(yīng)用修改了指向該對(duì)象的引用诵竭,使得它稱為了垃圾话告。但是CMS Collector無(wú)法將其檢測(cè)出來(lái)兼搏。因此它能夠躲過(guò)這一輪的垃圾回收,直到下一次的回收周期沙郭;

CMS Collector不是compacting的佛呻,這意味著垃圾回收之后得到的空閑空間并不是連續(xù)的。這會(huì)帶來(lái)一些問(wèn)題:

  1. 分配方式改變:前面提到的最多的分配方式就是bump-the-pointer病线。但是該分配方式只使用于連續(xù)的空閑空間吓著。CMS采用了新的分配方式:空閑鏈表分配方式,該概念和操作系統(tǒng)中內(nèi)存管理中的空閑鏈表是一樣的送挑;
  2. 空閑空間不連續(xù)會(huì)導(dǎo)致空間有效利用率下降绑莺。比如說(shuō)空閑空間總和是足以容納分配對(duì)象的,但是因?yàn)椴荒苋菁{惕耕,所以反而會(huì)觸發(fā)GC纺裁,或者會(huì)觸發(fā)擴(kuò)容。所以對(duì)于CMS Collector來(lái)說(shuō)司澎,它會(huì)要求更大的堆欺缘;
  3. CMS Collector會(huì)合并相鄰的空閑空間:這是一個(gè)優(yōu)化,但是因?yàn)楹喜⑦@個(gè)空閑空間需要操作空閑鏈表挤安,而分配對(duì)象又需要操作空閑鏈表谚殊,所以在concurrent sweep會(huì)出現(xiàn)空閑鏈表的爭(zhēng)用。CMS Collector使用了Mutual exclusion locks來(lái)保證JVM分配優(yōu)先蛤铜;

CMS Collector是允許整理空閑空間的嫩絮,用戶可以通過(guò)命令行選項(xiàng)UseCMSCompactAtFullCollection來(lái)指定。

CMS Collector還有一種模式围肥,增量模式(Incremental Mode)剿干。在該模式下,CMS Collector會(huì)使用少量的線程來(lái)并發(fā)標(biāo)記或者并發(fā)清掃虐先,整個(gè)過(guò)程會(huì)持續(xù)多個(gè)minor collection周期怨愤。該模式的好處是,可以降低pause time蛹批,并且減少對(duì)應(yīng)用的影響撰洗。所付出的代價(jià),就是需要更加大的堆腐芍。該模式一般適用于CPU數(shù)量較少的情況差导。

使用場(chǎng)景

適用于要求pause time盡可能短,并且擁有多個(gè)CPU的應(yīng)用猪勇。CMS Collector的別名是Latency Collector设褐。

影響因素和選項(xiàng)

在Serial Collector中談及的因素對(duì)CMS Collector都會(huì)有影響,此外還受到:

  1. 線程數(shù)量
  2. CPU數(shù)量
  3. CMSInitiatingOccupancyFraction:該選項(xiàng)設(shè)置了當(dāng)被分配內(nèi)存占據(jù)了多大比例的時(shí)候,就會(huì)觸發(fā)major collection助析。若是設(shè)置的太小犀被,那么會(huì)導(dǎo)致更加頻繁的GC;但是設(shè)置得太大外冀,就更有可能出現(xiàn)回收過(guò)程中空閑空間不足的現(xiàn)象寡键,而這會(huì)導(dǎo)致應(yīng)用被停下來(lái),直到GC完成雪隧;
  4. 是否使用增量模式

G1 Collector

原理

G1 Collector(Garbage-First Collector)可以被看做是CMS Collector的升級(jí)加強(qiáng)版西轩。G1 Collector的算法流程和CMS類似,所不同的有:

  1. G1 Collector采用的是標(biāo)記-整理算法脑沿。這意味著每次算法結(jié)束得到的都是連續(xù)空間藕畔;
  2. G1 Collector雖然還采用分代的方式,但是它的內(nèi)存模型有了巨大的變化庄拇。它的內(nèi)存基本結(jié)構(gòu)被分成了一個(gè)個(gè)Region注服。G1 Collector維護(hù)了一個(gè)Region的列表,每次判斷哪個(gè)Region的回收價(jià)值最大丛忆,便回收該Region祠汇。也就是說(shuō),G1 Collector回收并不是回收整個(gè)區(qū)域熄诡,而是分區(qū)域收集的;

其具體流程是:

  1. initial marking phase:標(biāo)記根诗力,該階段是stop-the-world式的凰浮;
  2. root region scanning phase:該階段標(biāo)記Survivor Region中的指向老年代的引用,及其引用對(duì)象苇本;
  3. Concurrent marking phase:
  4. Remark phase:
  5. Cleanup phase:

所以CMS Collector因?yàn)椴l(fā)引發(fā)的問(wèn)題G1也同樣存在袜茧。但是G1 Collector能夠避開(kāi)各種因?yàn)榭臻e空間不連續(xù)所導(dǎo)致的問(wèn)題。

G1 Collector實(shí)現(xiàn)的算法是比較復(fù)雜的瓣窄,詳細(xì)內(nèi)容可以閱讀Java Platform, Standard Edition HotSpot Virtual Machine Garbage Collection Tuning Guide和《垃圾回收算法手冊(cè)-自動(dòng)內(nèi)存管理的藝術(shù)》10.3.1笛厦,11.8.6等

G1 Collector有一個(gè)很重要的特性,就是“軟實(shí)時(shí)”俺夕。G1 Collector可以讓使用者指定在一個(gè)長(zhǎng)度為M毫秒的時(shí)間段內(nèi)裳凸,消耗在垃圾收集上的時(shí)間不得超過(guò)N毫秒。這已經(jīng)是期望達(dá)到一種類似于實(shí)時(shí)垃圾回收的效果了劝贸。

所謂的實(shí)時(shí)垃圾回收姨谷,是指必須能夠精確地控制由垃圾回收所導(dǎo)致的賦值器的中斷。

結(jié)語(yǔ)

強(qiáng)烈推薦閱讀Oracle上關(guān)于HotSpot的相關(guān)文檔映九,以及《垃圾回收算法手冊(cè)-自動(dòng)內(nèi)存管理的藝術(shù)》梦湘。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子捌议,更是在濱河造成了極大的恐慌哼拔,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件瓣颅,死亡現(xiàn)場(chǎng)離奇詭異管挟,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)弄捕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)僻孝,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)璧坟,“玉大人夺刑,你說(shuō)我怎么就攤上這事巷嚣〔徒” “怎么了互亮?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵命辖,是天一觀的道長(zhǎng)胎撤。 經(jīng)常有香客問(wèn)我创坞,道長(zhǎng)平酿,這世上最難降的妖魔是什么凤优? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮蜈彼,結(jié)果婚禮上筑辨,老公的妹妹穿的比我還像新娘。我一直安慰自己幸逆,他們只是感情好棍辕,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著还绘,像睡著了一般楚昭。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上拍顷,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天抚太,我揣著相機(jī)與錄音,去河邊找鬼昔案。 笑死尿贫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的爱沟。 我是一名探鬼主播帅霜,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼呼伸!你這毒婦竟也來(lái)了身冀?” 一聲冷哼從身側(cè)響起钝尸,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎搂根,沒(méi)想到半個(gè)月后珍促,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡剩愧,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年猪叙,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片仁卷。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡穴翩,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出锦积,到底是詐尸還是另有隱情芒帕,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布丰介,位于F島的核電站背蟆,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏哮幢。R本人自食惡果不足惜带膀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望橙垢。 院中可真熱鬧垛叨,春花似錦、人聲如沸钢悲。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)莺琳。三九已至,卻和暖如春载慈,著一層夾襖步出監(jiān)牢的瞬間惭等,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工办铡, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留辞做,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓寡具,卻偏偏與公主長(zhǎng)得像秤茅,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子童叠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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