查看垃圾回收器:
我們知道JVM分Client 和 Server模式簿煌。如果啟動JVM不指定模式,JDK會根據(jù)當(dāng)前的操作系統(tǒng)配置來啟動不同模式的JVM膜蛔。默認64bit操作系統(tǒng)下都會是Server模式的JVM灰殴。
不同垃圾收集器的區(qū)分:
新生代谐宙、老年代垃圾收集器,
單線程筝尾、多線程并行垃圾收集器捡需,
stop the world和并發(fā)(GC線程和用戶線程同時運行)的垃圾收集器
如果你運行在JVM的客戶端模式(Client)下,JVM默認垃圾收集器是串行垃圾收集器(Serial GC筹淫,-XX:+USeSerialGC)站辉;在JVM服務(wù)器模式(Server)下默認垃圾收集器是并行垃圾收集器(Parallel GC,-XX:+UseParallelGC)损姜。
JVM是一個進程饰剥,垃圾收集器就是一個線程,垃圾收集線程是一個守護線程摧阅,優(yōu)先級低汰蓉,其在當(dāng)前系統(tǒng)空閑或堆中老年代占用率較大時觸發(fā)。
守護線程是為其他線程服務(wù)的線程棒卷,調(diào)用start()方法前顾孽,調(diào)用setDaemon(true)把該線程標(biāo)記為守護線程祝钢。所有非守護線程都執(zhí)行完畢后,虛擬機退出若厚;守護線程不能持有需要關(guān)閉的資源(如打開文件等)拦英。
JDK7/8后,HotSpot虛擬機所有收集器及組合(連線)盹沈,如下圖:
圖中展示了7種不同分代的收集器:
Serial龄章、ParNew (Serial的升級版,多線程)乞封、Parallel Scavenge做裙、Serial Old、Parallel Old肃晚、CMS锚贱、G1
新生代收集器還是老年代收集器:
新生代收集器:Serial、ParNew关串、Parallel Scavenge拧廊;
老年代收集器:Serial Old、Parallel Old晋修、CMS吧碾;
整堆收集器:G1
吞吐量優(yōu)先、停頓時間優(yōu)先
吞吐量優(yōu)先:Parallel Scavenge收集器墓卦、Parallel Old 收集器倦春。
停頓時間優(yōu)先:CMS(Concurrent Mark-Sweep)收集器。
吞吐量與停頓時間適用場景
停頓時間優(yōu)先:交互多落剪,對響應(yīng)速度要求高(對外系統(tǒng))
吞吐量優(yōu)先:交互少睁本,計算多,適合在后臺運算的場景(對內(nèi)系統(tǒng))忠怖。
串行并行并發(fā)
串行:Serial呢堰、Serial Old
并行:ParNew、Parallel Scavenge凡泣、Parallel Old
并發(fā):CMS枉疼、G1
算法
復(fù)制算法:Serial、ParNew问麸、Parallel Scavenge往衷、G1
標(biāo)記-清除:CMS
標(biāo)記-整理:Serial Old、Parallel Old严卖、G1
并行和并發(fā)的區(qū)別:
并行(Parallel)席舍,同時處理多個任務(wù),時間點哮笆。
并發(fā)(Concurrent),處理多任務(wù),不一定同時德崭,時間間隔。
1萝毛、Serial收集器
Serial(串行)垃圾收集器是最基本、發(fā)展歷史最悠久的收集器滑黔;
JDK1.3.1前是HotSpot新生代收集的唯一選擇笆包;
特點
針對新生代,串行略荡,復(fù)制算法庵佣,單線程一方面意味著它只會使用一個CPU或一條線程去完成垃圾收集工作,另一方面也意味著在它進行垃圾收集時汛兜,必須暫停其他所有的工作線程巴粪,直到它收集結(jié)束為止,這個過程也稱為 Stop The world粥谬。后者意味著肛根,在用戶不可見的情況下要把用戶正常工作的線程全部停掉,這顯然對很多應(yīng)用是難以接受的漏策。
應(yīng)用場景
對于限定單個CPU的環(huán)境來說派哲,Serial收集器由于沒有線程交互的開銷,專心做垃圾收集自然可以獲得最高的單線程收集效率掺喻。
Serial收集器依然是虛擬機運行在Client模式下的默認新生代收集器狮辽。?在用戶的桌面應(yīng)用場景中,可用內(nèi)存一般不大(幾十M至一兩百M)巢寡,可以在較短時間內(nèi)完成垃圾收集(幾十MS至一百多MS),只要不頻繁發(fā)生,這是可以接受的
Tips:Stop the World是在用戶不可見的情況下執(zhí)行的椰苟,會造成某些應(yīng)用響應(yīng)變慢抑月;
Tips:因為新生代的特點是對象存活率低,所以收集算法用的是復(fù)制算法舆蝴,把新生代存活對象復(fù)制到老年代谦絮,復(fù)制的內(nèi)容不多,性能較好洁仗。
Tips:單線程地好處就是減少上下文切換层皱,減少系統(tǒng)資源的開銷。但這種方式的缺點也很明顯赠潦,在GC的過程中叫胖,會暫停程序的執(zhí)行。若GC不是頻繁發(fā)生她奥,這或許是一個不錯的選擇瓮增,否則將會影響程序的執(zhí)行性能怎棱。 對于新生代來說,區(qū)域比較小绷跑,停頓時間短拳恋,所以比較使用。
參數(shù)
-XX:+UseSerialGC:串聯(lián)收集器
Tips:在JDK Client模式砸捏,不指定VM參數(shù)谬运,默認是串行垃圾回收器
2、ParNew收集器
ParNew收集器的工作過程如下圖:
ParNew收集器就是Serial收集器的多線程版本垦藏,它也是一個新生代收集器梆暖。除了使用多線程進行垃圾收集外,其余行為包括Serial收集器可用的所有控制參數(shù)膝藕、收集算法(復(fù)制算法)式廷、Stop The World、對象分配規(guī)則芭挽、回收策略等與Serial收集器完全相同滑废,兩者共用了相當(dāng)多的代碼。
ParNew收集器除了使用多線程收集外袜爪,其他與Serial收集器相比并無太多創(chuàng)新之處蠕趁,但它卻是許多運行在Server模式下的虛擬機中首選的新生代收集器,其中有一個與性能無關(guān)的重要原因是辛馆,除了Serial收集器外俺陋,目前只有它能和CMS收集器(Concurrent Mark Sweep)配合工作,CMS收集器是JDK 1.5推出的一個具有劃時代意義的收集器昙篙,具體內(nèi)容將在稍后進行介紹腊状。
ParNew 收集器在單CPU的環(huán)境中絕對不會有比Serial收集器有更好的效果,甚至由于存在線程交互的開銷苔可,該收集器在通過超線程技術(shù)實現(xiàn)的兩個CPU的環(huán)境中都不能百分之百地保證可以超越缴挖。在多CPU環(huán)境下,隨著CPU的數(shù)量增加焚辅,它對于GC時系統(tǒng)資源的有效利用是很有好處的映屋。
特點
ParNew收集器其實就是Serial收集器的多線程版本,除了使用多條線程進行垃圾收集外同蜻,其余行為和Serial收集器完全一樣棚点,包括Serial收集器可用的所有控制參數(shù)、收集算法湾蔓、Stop The world瘫析、對象分配規(guī)則、回收策略等都一樣。在實現(xiàn)上也共用了相當(dāng)多的代碼颁股。
針對新生代
復(fù)制算法
串行
多線程
GC時需要暫停所有用戶線程么库,直到GC結(jié)束
Serial多線程版本,其他特點與Serial相同
應(yīng)用場景
ParNew收集器是許多運行在Server模式下的虛擬機中首選的新生代收集器甘有。很重要的原因是:除了Serial收集器之外诉儒,目前只有它能與CMS收集器配合工作(看圖)。在JDK1.5時期亏掀,HotSpot推出了一款幾乎可以認為具有劃時代意義的垃圾收集器-----CMS收集器忱反,這款收集器是HotSpot虛擬機中第一款真正意義上的并發(fā)收集器,它第一次實現(xiàn)了讓垃圾收集線程與用戶線程同時工作滤愕。
參數(shù)
"-XX:+UseConcMarkSweepGC":指定使用CMS后温算,會默認使用ParNew作為新生代收集器;
"-XX:+UseParNewGC":強制指定使用ParNew间影;????
"-XX:ParallelGCThreads":指定垃圾收集的線程數(shù)量注竿,ParNew默認開啟的收集線程與CPU的數(shù)量相同;
為什么只有ParNew能與CMS收集器配合
CMS是HotSpot在JDK1.5推出的第一款真正意義上的并發(fā)(Concurrent)收集器魂贬,第一次實現(xiàn)了讓垃圾收集線程與用戶線程(基本上)同時工作巩割;
CMS作為老年代收集器,但卻無法與JDK1.4已經(jīng)存在的新生代收集器Parallel Scavenge配合工作付燥;
因為Parallel Scavenge(以及G1)都沒有使用傳統(tǒng)的GC收集器代碼框架宣谈,而另外獨立實現(xiàn);而其余幾種收集器則共用了部分的框架代碼键科;
3闻丑、Parallel Scavenge收集器
Parallel Scavenge收集器和ParNew類似,新生代的收集器勋颖,同樣用的是復(fù)制算法嗦嗡,也是并行多線程收集。與ParNew最大的不同饭玲,它關(guān)注的是垃圾回收的吞吐量酸钦。
特點
針對新生代、復(fù)制算法咱枉、并行、多線程徒恋、高吞吐量為目標(biāo)
應(yīng)用場景
Parallel Scavenge收集器是虛擬機運行在Server模式下的默認垃圾收集器蚕断。
高吞吐量為目標(biāo),即減少垃圾收集時間入挣,讓用戶代碼獲得更長的運行時間亿乳;適合那種交互少、運算多的場景
例如,那些執(zhí)行批量處理葛假、訂單處理障陶、工資支付、科學(xué)計算的應(yīng)用程序聊训;
參數(shù)
"-XX:+MaxGCPauseMillis":控制最大垃圾收集停頓時間抱究,大于0的毫秒數(shù);這個參數(shù)設(shè)置的越小带斑,停頓時間可能會縮短鼓寺,但也會導(dǎo)致吞吐量下降,導(dǎo)致垃圾收集發(fā)生得更頻繁勋磕。
"-XX:GCTimeRatio":設(shè)置垃圾收集時間占總時間的比率妈候,0<n<100的整數(shù),就相當(dāng)于設(shè)置吞吐量的大小挂滓。
先垃圾收集執(zhí)行時間占應(yīng)用程序執(zhí)行時間的比例的計算方法是:
1 / (1 + n)
例如苦银,選項-XX:GCTimeRatio=19,設(shè)置了垃圾收集時間占總時間的5%=1/(1+19)赶站;
默認值是1%--1/(1+99)幔虏,即n=99;
垃圾收集所花費的時間是年輕一代和老年代收集的總時間亲怠;
此外所计,還有一個值得關(guān)注的參數(shù):
"-XX:+UseAdptiveSizePolicy"
開啟這個參數(shù)后,就不用手工指定一些細節(jié)參數(shù)团秽,如:
新生代的大兄麟省(-Xmn)、Eden與Survivor區(qū)的比例(-XX:SurvivorRation)习勤、晉升老年代的對象年齡(-XX:PretenureSizeThreshold)等踪栋;
JVM會根據(jù)當(dāng)前系統(tǒng)運行情況收集性能監(jiān)控信息,動態(tài)調(diào)整這些參數(shù)图毕,以提供最合適的停頓時間或最大的吞吐量夷都,這種調(diào)節(jié)方式稱為GC自適應(yīng)的調(diào)節(jié)策略(GC Ergonomiscs);????
另外值得注意的一點是予颤,Parallel Scavenge收集器無法與CMS收集器配合使用囤官,所以在JDK 1.6推出Parallel Old之前,如果新生代選擇Parallel Scavenge收集器蛤虐,老年代只有Serial Old收集器能與之配合使用党饮。
Parallel Scavenge收集器 VS CMS等收集器:
Parallel Scavenge收集器的特點是它的關(guān)注點與其他收集器不同,CMS等收集器的關(guān)注點是盡可能地縮短垃圾收集時用戶線程的停頓時間驳庭,而Parallel Scavenge收集器的目標(biāo)則是達到一個可控制的吞吐量(Throughput)刑顺。
由于與吞吐量關(guān)系密切氯窍,Parallel Scavenge收集器也經(jīng)常稱為“吞吐量優(yōu)先”收集器。
Parallel Scavenge收集器 VS ParNew收集器:
Parallel Scavenge收集器與ParNew收集器的一個重要區(qū)別是它具有自適應(yīng)調(diào)節(jié)策略蹲堂。
4狼讨、Serial Old收集器(標(biāo)記-整理算法)
Serial收集器的工作流程如下圖:
如上圖所示,Serial 收集器在新生代和老年代都有對應(yīng)的版本柒竞,除了收集算法不同政供,兩個版本并沒有其他差異。
Serial 新生代收集器采用的是復(fù)制算法能犯。
Serial Old 老年代采用的是標(biāo)記 - 整理算法鲫骗。
特性
Serial Old是Serial的老年代版本,
除了采用標(biāo)記-整理算法踩晶,其他與Serial相同
應(yīng)用場景
Client模式
Serial Old收集器的主要意義也是在于給Client模式下的虛擬機使用执泰。
Server模式
如果在Server模式下,那么它主要還有兩大用途:一種用途是在JDK 1.5以及之前的版本中與Parallel Scavenge收集器搭配使用渡蜻;另一種用途就是作為CMS收集器的后備預(yù)案术吝,在并發(fā)收集發(fā)生"Concurrent Mode Failure"時使用。
5茸苇、Parallel Old收集器
如上圖所示排苍,Parallel 收集器在新生代和老年代也都有對應(yīng)的版本,除了收集算法不同学密,兩個版本并沒有其他差異淘衙。
Parallel Scavenge收集器的老年代版本,并行收集器腻暮,吞吐量優(yōu)先
Parallel Old收集器是Parallel Scavenge收集器的老年版本彤守,它也使用多線程和“標(biāo)記-整理”算法。這個收集器是在JDK 1.6開始提供哭靖。
Mark-Compact
特點
Parallel Old是Parallel Scavenge的老年代版本
Parallel Old 老年代采用的是標(biāo)記 - 整理算法具垫,其他特點與Parallel Scavenge相同
使用場景
在注重吞吐量以及CPU資源敏感的場合,都可以優(yōu)先考慮Parallel Scavenge加Parallel Old收集器組合试幽。
JDK1.6及之后用來代替老年代的Serial Old收集器筝蚕;
特別是在Server模式,多CPU的情況下铺坞;
參數(shù)
-XX:+UseParallelOldGC:指定使用Parallel Old收集器起宽;
6、CMS(Concurrent Mark Sweep济榨,并發(fā)標(biāo)記清除)收集器
概述
CMS是HotSpot在JDK5推出的第一款真正意義上的并發(fā)(Concurrent)收集器燎含,第一次實現(xiàn)了讓垃圾收集線程與用戶線程(基本上)同時工作;
命名中用的是concurrent腿短,而不是parallel,說明這個收集器是有與工作執(zhí)行并發(fā)的能力的。MS則說明算法用的是Mark Sweep算法橘忱。
它關(guān)注的是垃圾回收最短的停頓時間(低停頓)赴魁,在老年代并不頻繁GC的場景下,是比較適用的钝诚。
特點
針對老年代
標(biāo)記-清除算法 (不進行壓縮操作颖御,產(chǎn)生內(nèi)存碎片);
并發(fā)凝颇,多線程潘拱,收集過程中不需要暫停用戶線程,以獲取最短回收停頓時間為目標(biāo)拧略。
應(yīng)用場景
與用戶交互較多的場景芦岂。CMS 收集器是一種以獲取最短回收停頓時間為目標(biāo)的收集器。目前很大一部分的Java應(yīng)用集中在互聯(lián)網(wǎng)或者B/S系統(tǒng)的服務(wù)端上垫蛆,這類應(yīng)用尤其注重服務(wù)的響應(yīng)速度禽最,希望系統(tǒng)停頓時間最短,以給用戶帶來極好的體驗袱饭。CMS收集器就非常符合這類應(yīng)用的需求川无。
CMS是一種以獲取最短回收停頓時間為目標(biāo)的收集器。在重視響應(yīng)速度和用戶體驗的應(yīng)用中虑乖,CMS應(yīng)用很多懦趋。
CMS GC過程分四步完成:
比前面幾種收集器更復(fù)雜,可以分為4個步驟:
1疹味、初始標(biāo)記(initial mark)
單線程執(zhí)行
需要“Stop The World”
但僅僅把GC Roots的直接關(guān)聯(lián)可達的對象給標(biāo)記一下仅叫,由于直接關(guān)聯(lián)對象比較小,所以這里的速度非撤鹈停快
2惑芭、并發(fā)標(biāo)記(concurrent mark)
對于初始標(biāo)記過程所標(biāo)記的初始標(biāo)記對象,進行并發(fā)追蹤標(biāo)記继找,
此時其他線程仍可以繼續(xù)工作遂跟。
此處時間較長,但不停頓婴渡。
并不能保證可以標(biāo)記出所有的存活對象幻锁;
3、重新標(biāo)記(remark)
在并發(fā)標(biāo)記的過程中边臼,由于可能還會產(chǎn)生新的垃圾哄尔,所以此時需要重新標(biāo)記新產(chǎn)生的垃圾。
此處執(zhí)行并行標(biāo)記柠并,與用戶線程不并發(fā)岭接,所以依然是“Stop The World”富拗,
且停頓時間比初始標(biāo)記稍長,但遠比并發(fā)標(biāo)記短鸣戴。
4啃沪、并發(fā)清除(concurrent sweep)
并發(fā)清除之前所標(biāo)記的垃圾。
其他用戶線程仍可以工作窄锅,不需要停頓创千。
Tips:其中,初始標(biāo)記和并發(fā)標(biāo)記仍然需要Stop the World入偷、初始標(biāo)記僅僅標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對象追驴,速度很快,并發(fā)標(biāo)記就是進行GC RootsTracing的過程疏之,而重新標(biāo)記階段則是為了修正并發(fā)標(biāo)記期間因用戶程序繼續(xù)運行而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記記錄殿雪,這個階段的停頓時間一般會比初始標(biāo)記階段長,但遠比并發(fā)標(biāo)記的時間短体捏。
由于整個過程中耗時最長的并發(fā)標(biāo)記和并發(fā)清除過程收集器線程都可以與用戶線程一起工作冠摄,所以整體上說,CMS收集器的內(nèi)存回收過程是與用戶線程一共并發(fā)執(zhí)行的几缭。
參數(shù)
-XX:+UseConcMarkSweepGC:使用CMS收集器
-XX:+ UseCMSCompactAtFullCollection:Full GC后河泳,進行一次碎片整理;整理過程是獨占的年栓,會引起停頓時間變長
-XX:+CMSFullGCsBeforeCompaction:設(shè)置進行幾次Full GC后拆挥,進行一次碎片整理
-XX:ParallelCMSThreads:設(shè)定CMS的線程數(shù)量(一般情況約等于可用CPU數(shù)量)?
缺點
總體來看,與Parallel Old垃圾收集器相比某抓,CMS減少了執(zhí)行老年代垃圾收集時應(yīng)用暫停的時間纸兔;
但卻增加了新生代垃圾收集時應(yīng)用暫停的時間、降低了吞吐量而且需要占用更大的堆空間否副;
由于最耗費時間的并發(fā)標(biāo)記與并發(fā)清除階段都不需要暫停工作汉矿,所以整體的回收是低停頓的。
由于CMS以上特性备禀,缺點也是比較明顯的洲拇,
1、對CPU資源非常敏感
對CPU資源非常敏感 其實曲尸,面向并發(fā)設(shè)計的程序都對CPU資源比較敏感赋续。
在并發(fā)階段,它雖然不會導(dǎo)致用戶線程停頓另患,但會因為占用了一部分線程(或者說CPU資源)而導(dǎo)致應(yīng)用程序變慢纽乱,總吞吐量會降低。
CMS默認啟動的回收線程數(shù)是(CPU數(shù)量+3)/4昆箕,也就是當(dāng)CPU在4個以上時鸦列,并發(fā)回收時垃圾收集線程不少于25%的CPU資源租冠,并且隨著CPU數(shù)量的增加而下降。
但是當(dāng)CPU不足4個時(比如2個)薯嗤,CMS對用戶程序的影響就可能變得很大肺稀,如果本來CPU負載就比較大,還要分出一半的運算能力去執(zhí)行收集器線程应民,就可能導(dǎo)致用戶程序的執(zhí)行速度忽然降低了50%,其實也讓人無法接受夕吻。
并發(fā)收集雖然不會暫停用戶線程诲锹,但因為占用一部分CPU資源,還是會導(dǎo)致應(yīng)用程序變慢涉馅,總吞吐量降低归园。
CMS的默認收集線程數(shù)量是=(CPU數(shù)量+3)/4;
當(dāng)CPU數(shù)量多于4個稚矿,收集線程占用的CPU資源多于25%庸诱,對用戶程序影響可能較大;不足4個時晤揣,影響更大桥爽,可能無法接受。
2昧识、浮動垃圾(Floating Garbage)
由于CMS并發(fā)清理階段用戶線程還在運行著钠四,伴隨程序運行自然就還會有新的垃圾不斷產(chǎn)生,這一部分垃圾出現(xiàn)在標(biāo)記過程之后跪楞,CMS無法在當(dāng)次收集中處理掉它們缀去,只好留待下一次GC時再清理掉。這一部分垃圾就稱為“浮動垃圾”甸祭。
由于在垃圾收集階段用戶線程還需要運行缕碎,那就還需要預(yù)留有足夠的內(nèi)存空間給用戶線程使用,因此CMS收集器不能像其他收集器那樣等到老年代幾乎完全被填滿了再進行收集池户,也可以認為CMS所需要的空間比其他垃圾收集器大咏雌;
??????"-XX:CMSInitiatingOccupancyFraction":設(shè)置CMS預(yù)留內(nèi)存空間;
??????JDK1.5默認值為68%煞檩;
??????JDK1.6變?yōu)榇蠹s92%处嫌;
3、"Concurrent Mode Failure"失敗
如果CMS運行期間預(yù)留的內(nèi)存無法滿足程序需要斟湃,就會出現(xiàn)一次“Concurrent Mode Failure”失敗熏迹,這時虛擬機將啟動后備預(yù)案:臨時啟用Serial Old收集器來重新進行老年代的垃圾收集,這樣會導(dǎo)致另一次Full GC的產(chǎn)生凝赛。這樣停頓時間就更長了注暗,代價會更大坛缕,所以?"-XX:CMSInitiatingOccupancyFraction"不能設(shè)置得太大。
4捆昏、產(chǎn)生大量內(nèi)存碎片
這個問題并不是CMS的問題赚楚,而是算法的問題。由于CMS基于"標(biāo)記-清除"算法骗卜,清除后不進行壓縮操作宠页,所以會產(chǎn)生碎片
"標(biāo)記-清除"算法介紹時曾說過:
產(chǎn)生大量不連續(xù)的內(nèi)存碎片會導(dǎo)致分配大內(nèi)存對象時,無法找到足夠的連續(xù)內(nèi)存寇仓,從而需要提前觸發(fā)另一次Full GC動作举户。
4.1碎片解決方法:
(1)、"-XX:+UseCMSCompactAtFullCollection"
??????使得CMS出現(xiàn)上面這種情況時不進行Full GC遍烦,而開啟內(nèi)存碎片的合并整理過程俭嘁;
??????但合并整理過程無法并發(fā),停頓時間會變長服猪;
??????默認開啟(但不會進行供填,結(jié)合下面的CMSFullGCsBeforeCompaction);
(2)罢猪、"-XX:+CMSFullGCsBeforeCompaction"
??????設(shè)置執(zhí)行多少次不壓縮的Full GC后近她,來一次壓縮整理;
??????為減少合并整理過程的停頓時間坡脐;
??????默認為0泄私,也就是說每次都執(zhí)行Full GC,不會進行壓縮整理备闲;
??????由于空間不再連續(xù)晌端,CMS需要使用可用"空閑列表"內(nèi)存分配方式,這比簡單實用"碰撞指針"分配內(nèi)存消耗大恬砂;
CMS為什么沒有采用標(biāo)記整理算法咧纠?:
分代式GC里,年老代常用mark-sweep泻骤;或者是mark-sweep/mark-compact的混合方式漆羔,一般情況下用mark-sweep,統(tǒng)計估算碎片量達到一定程度時用mark-compact狱掂。這是因為傳統(tǒng)上大家認為年老代的對象可能會長時間存活且存活率高演痒,或者是比較大,這樣拷貝起來不劃算趋惨,還不如采用就地收集的方式鸟顺。Mark-sweep、mark-compact、copying這三種基本算法里讯嫂,只有mark-sweep是不移動對象(也就是不用拷貝)的蹦锋,所以選用mark-sweep。
7欧芽、G1收集器
概述
G1(Garbage - First)名稱的由來是G1跟蹤各個Region里面的垃圾堆的價值大欣虻唷(回收所獲得的空間大小以及回收所需時間的經(jīng)驗值),在后臺維護一個優(yōu)先列表千扔,每次根據(jù)允許的收集時間憎妙,優(yōu)先回收價值最大的Region。
G1(Garbage-First)是JDK7-u4才推出商用的收集器曲楚;
注意:G1與前面的垃圾收集器有很大不同尚氛,它把新生代、老年代的劃分取消了洞渤!
這樣我們再也不用單獨的空間對每個代進行設(shè)置了,不用擔(dān)心每個代內(nèi)存是否足夠属瓣。
取而代之的是载迄,G1算法將堆劃分為若干個區(qū)域(Region),它仍然屬于分代收集器抡蛙。不過护昧,這些區(qū)域的一部分包含新生代,新生代的垃圾收集依然采用暫停所有應(yīng)用線程的方式粗截,將存活對象拷貝到老年代或者Survivor空間惋耙。老年代也分成很多區(qū)域,G1收集器通過將對象從一個區(qū)域復(fù)制到另外一個區(qū)域熊昌,完成了清理工作绽榛。這就意味著,在正常的處理過程中婿屹,G1完成了堆的壓縮(至少是部分堆的壓縮)灭美,這樣也就不會有CMS內(nèi)存碎片問題的存在了。
在G1中昂利,還有一種特殊的區(qū)域届腐,叫Humongous區(qū)域。 如果一個對象占用的空間超過了分區(qū)容量50%以上蜂奸,G1收集器就認為這是一個巨型對象犁苏。這些巨型對象,默認直接會被分配在年老代扩所,但是如果它是一個短期存在的巨型對象围详,就會對垃圾收集器造成負面影響。為了解決這個問題碌奉,G1劃分了一個Humongous區(qū)短曾,它用來專門存放巨型對象寒砖。如果一個H區(qū)裝不下一個巨型對象,那么G1會尋找連續(xù)的H分區(qū)來存儲嫉拐。為了能找到連續(xù)的H區(qū)哩都,有時候不得不啟動Full GC。
PS:在java 8中婉徘,持久代也移動到了普通的堆內(nèi)存空間中漠嵌,改為元空間。
特點
G1除了降低停頓外盖呼,還能建立可預(yù)測的停頓時間模型儒鹿;
1、Region概念
橫跨整個堆內(nèi)存
在G1之前的其他收集器進行收集的范圍都是整個新生代或者老生代几晤,而G1不再是這樣约炎。
G1在使用時,Java堆的內(nèi)存布局與其他收集器有很大區(qū)別蟹瘾,它將整個Java堆劃分為多個大小相等的獨立區(qū)域(Region)圾浅,雖然還保留新生代和老年代的概念,但新生代和老年代不再是物理隔離的了憾朴,而都是一部分Region(可以不連續(xù))的集合狸捕。
2、可并行众雷,可并發(fā)
能充分利用多CPU灸拍、多核環(huán)境下的硬件優(yōu)勢;
G1 能充分利用多CPU砾省、多核環(huán)境下的硬件優(yōu)勢鸡岗,使用多個CPU來縮短“Stop The World”停頓時間
并行:使用多個CPU來縮短Stop-The-World停頓的時間,
并發(fā):也可以并發(fā)讓垃圾收集與用戶程序同時進行
3编兄、分代收集纤房,收集范圍包括新生代和老年代?
能獨立管理整個GC堆(新生代和老年代),而不需要與其他收集器搭配翻诉;
能夠采用不同方式處理不同時期的對象炮姨;
4、空間整合碰煌,不產(chǎn)生碎片
從整體看舒岸,是基于標(biāo)記-整理算法;
從局部(兩個Region間)看芦圾,是基于復(fù)制算法蛾派;
都不會產(chǎn)生內(nèi)存碎片,有利于長時間運行;
這種特性有利于程序長時間運行洪乍,分配大對象時不會因為無法找到連續(xù)內(nèi)存空間而提前觸發(fā)下一次GC眯杏。
5、可預(yù)測的停頓:低停頓的同時實現(xiàn)高吞吐量
G1收集器之所以能建立可預(yù)測的停頓時間模型壳澳,是因為它可以有計劃地避免在整個Java堆中進行全區(qū)域的垃圾收集岂贩。
G1跟蹤各個Region里面的垃圾堆積的價值大小(回收所獲得的空間大小以及回收所需時間的經(jīng)驗值)巷波,在后臺維護一個優(yōu)先列表萎津,每次根據(jù)允許的收集時間,優(yōu)先回收價值最大的Region抹镊,這樣就保證了在有限的時間內(nèi)盡可能提高效率锉屈。(這也就是Garbage-First名稱的來由)。
這種使用Region劃分內(nèi)存空間以及有優(yōu)先級的區(qū)域回收方式垮耳,保證了G1收集器在有限的時間內(nèi)可以獲取盡可能高的收集效率颈渊。
應(yīng)用場景
如果你的應(yīng)用追求低停頓,那G1現(xiàn)在已經(jīng)可以作為一個可嘗試選擇终佛,如果你的應(yīng)用追求吞吐量儡炼,那G1并不會為你帶來什么特別的好處娘荡。
1.面向服務(wù)端應(yīng)用,針對具有大內(nèi)存届巩、多處理器的機器营密;最主要的應(yīng)用是為需要低GC延遲,并具有大堆的應(yīng)用程序提供解決方案契讲;
如:在堆大小約6GB或更大時,可預(yù)測的暫停時間可以低于0.5秒;
2.用來替換掉JDK1.5的CMS收集器鹃共;
(1)、超過50%的Java堆被活動數(shù)據(jù)占用驶拱;
(2)霜浴、對象分配頻率或年代提升頻率變化很大;
(3)蓝纲、GC停頓時間過長(長與0.5至1秒)阴孟。
參數(shù)
"-XX:+UseG1GC":指定使用G1收集器;
"-XX:InitiatingHeapOccupancyPercent":當(dāng)整個Java堆的占用率達到參數(shù)值時税迷,開始并發(fā)標(biāo)記階段永丝;默認為45;
"-XX:MaxGCPauseMillis":為G1設(shè)置暫停時間目標(biāo)箭养,默認值為200毫秒慕嚷;
"-XX:G1HeapRegionSize":設(shè)置每個Region大小,范圍1MB到32MB;目標(biāo)是在最小Java堆時可以擁有約2048個Region喝检;
為什么G1收集器可以實現(xiàn)可預(yù)測的停頓嗅辣?
G1可以建立可預(yù)測的停頓時間模型,是因為:
無論G1還是其他分代收集器挠说,JVM都是使用Remembered Set來避免全局掃描澡谭,每個Region都有一個對應(yīng)的Remembered Set;每次Reference類型數(shù)據(jù)寫操作時纺涤,都會產(chǎn)生一個Write Barrier暫時中斷操作译暂;然后檢查將要寫入的引用指向的對象是否和該Reference類型數(shù)據(jù)在不同的Region(其他收集器:檢查老年代對象是否引用了新生代對象);如果不同撩炊,通過CardTable把相關(guān)引用信息記錄到引用指向?qū)ο蟮乃赗egion對應(yīng)的Remembered Set中外永;當(dāng)進行垃圾收集時,在GC根節(jié)點的枚舉范圍加入Remembered Set拧咳;就可以保證不進行全局掃描伯顶,也不會有遺漏。
可以有計劃地避免在Java堆的進行全區(qū)域的垃圾收集骆膝;
G1跟蹤各個Region獲得其收集價值大小祭衩,在后臺維護一個優(yōu)先列表;
每次根據(jù)允許的收集時間(如何設(shè)置阅签,有哪些參數(shù)掐暮??政钟?)路克,優(yōu)先回收價值最大的Region(名稱Garbage-First的由來);
這就保證了在有限的時間內(nèi)可以獲取盡可能高的收集效率养交;
G1收集器運作過程
不計算維護Remembered Set的操作精算,可以分為4個步驟(與CMS較為相似)。
1碎连、初始標(biāo)記(Initial Marking)
初始標(biāo)記僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對象灰羽,
速度很快,
需要“Stop The World”鱼辙。(OopMap)
2廉嚼、并發(fā)標(biāo)記(Concurrent Marking)
進行GC Roots Tracing的過程,從剛才產(chǎn)生的集合中標(biāo)記出存活對象倒戏;(也就是從GC Roots 開始對堆進行可達性分析前鹅,找出存活對象。)
耗時較長峭梳,但應(yīng)用程序也在運行舰绘;
并不能保證可以標(biāo)記出所有的存活對象蹂喻;
3、最終標(biāo)記(Final Marking)
最終標(biāo)記和CMS的重新標(biāo)記階段一樣捂寿,也是為了修正并發(fā)標(biāo)記期間因用戶程序繼續(xù)運作而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記記錄口四,
這個階段的停頓時間一般會比初始標(biāo)記階段稍長一些,但遠比并發(fā)標(biāo)記的時間短秦陋,
也需要“Stop The World”蔓彩。(修正Remebered Set)
4、篩選回收(Live Data Counting and Evacuation)
首先排序各個Region的回收價值和成本驳概;
然后根據(jù)用戶期望的GC停頓時間來制定回收計劃赤嚼;
最后按計劃回收一些價值高的Region中垃圾對象;
回收時采用"復(fù)制"算法顺又,從一個或多個Region復(fù)制存活對象到堆上的另一個空的Region更卒,并且在此過程中壓縮和釋放內(nèi)存;
可以并發(fā)進行稚照,降低停頓時間蹂空,并增加吞吐量;
參數(shù)
"-XX:+UseG1GC":指定使用G1收集器果录;
"-XX:InitiatingHeapOccupancyPercent":當(dāng)整個Java堆的占用率達到參數(shù)值時上枕,開始并發(fā)標(biāo)記階段;默認為45弱恒;
"-XX:MaxGCPauseMillis":為G1設(shè)置暫停時間目標(biāo)辨萍,默認值為200毫秒;
"-XX:G1HeapRegionSize":設(shè)置每個Region大小返弹,范圍1MB到32MB锈玉;目標(biāo)是在最小Java堆時可以擁有約2048個
總結(jié):
圖中展示了7種作用于不同分代的收集器,如果兩個收集器之間存在連線琉苇,就說明它們可以搭配使用。
虛擬機所處的區(qū)域悦施,則表示它是屬于新生代收集器還是老年代收集器并扇。
收集器總結(jié):
參數(shù)總結(jié):
ZGC
概述
在JDK 11當(dāng)中,加入了實驗性質(zhì)的ZGC抡诞。它的回收耗時平均不到2毫秒穷蛹。它是一款低停頓高并發(fā)的收集器。
ZGC幾乎在所有地方并發(fā)執(zhí)行的昼汗,除了初始標(biāo)記的是STW的肴熏。所以停頓時間幾乎就耗費在初始標(biāo)記上,這部分的實際是非常少的顷窒。那么其他階段是怎么做到可以并發(fā)執(zhí)行的呢蛙吏?
ZGC主要新增了兩項技術(shù)源哩,一個是著色指針Colored Pointer,另一個是讀屏障Load Barrier鸦做。
ZGC 是一個并發(fā)励烦、基于區(qū)域(region)、增量式壓縮的收集器泼诱。Stop-The-World 階段只會在根對象掃描(root scanning)階段發(fā)生坛掠,這樣的話 GC 暫停時間并不會隨著堆和存活對象的數(shù)量而增加。
ZGC 的設(shè)計目標(biāo)
TB 級別的堆內(nèi)存管理治筒;
最大?GC Pause?不高于?10ms屉栓;
最大的吞吐率(Throughput)損耗不高于?15%;
關(guān)鍵點:GC Pause?不會隨著 堆大小的增加 而增大耸袜。
ZGC 中關(guān)鍵技術(shù)
加載屏障(Load barriers)技術(shù)友多;
有色對象指針(Colored pointers);
單一分代內(nèi)存管理(這一點很有意思)句灌;
基于區(qū)域的內(nèi)存管理夷陋;
部分內(nèi)存壓縮;
即時內(nèi)存復(fù)用胰锌。
并行化處理階段
標(biāo)記(Marking);
重定位(Relocation)/壓縮(Compaction)骗绕;
重新分配集的選擇(Relocation set selection);
引用處理(Reference processing)资昧;
弱引用的清理(WeakRefs Cleaning);
字符串常量池(String Table)和符號表(Symbol Table)的清理酬土;
類卸載(Class unloading)。
著色指針Colored Pointer
ZGC利用指針的64位中的幾位表示Finalizable格带、Remapped撤缴、Marked1、Marked0(ZGC僅支持64位平臺)叽唱,以標(biāo)記該指向內(nèi)存的存儲狀態(tài)屈呕。相當(dāng)于在對象的指針上標(biāo)注了對象的信息。注意棺亭,這里的指針相當(dāng)于Java術(shù)語當(dāng)中的引用虎眨。
在這個被指向的內(nèi)存發(fā)生變化的時候(內(nèi)存在Compact被移動時),顏色就會發(fā)生變化镶摘。
在G1的時候就說到過嗽桩,Compact階段是需要STW,否則會影響用戶線程執(zhí)行凄敢。那么怎么解決這個問題呢碌冶?
讀屏障Load Barrier
由于著色指針的存在,在程序運行時訪問對象的時候涝缝,可以輕易知道對象在內(nèi)存的存儲狀態(tài)(通過指針訪問對象)扑庞,若請求讀的內(nèi)存在被著色了譬重,那么則會觸發(fā)讀屏障。讀屏障會更新指針再返回結(jié)果嫩挤,此過程有一定的耗費害幅,從而達到與用戶線程并發(fā)的效果。
把這兩項技術(shù)聯(lián)合下理解岂昭,引用R大(RednaxelaFX)的話
與標(biāo)記對象的傳統(tǒng)算法相比以现,ZGC在指針上做標(biāo)記,在訪問指針時加入Load Barrier(讀屏障)约啊,比如當(dāng)對象正被GC移動邑遏,指針上的顏色就會不對,這個屏障就會先把指針更新為有效地址再返回恰矩,也就是记盒,永遠只有單個對象讀取時有概率被減速,而不存在為了保持應(yīng)用與GC一致而粗暴整體的Stop The World外傅。
ZGC雖然目前還在JDK 11還在實驗階段纪吮,但由于算法與思想是一個非常大的提升,相信在未來不久會成為主流的GC收集器使用萎胰。
參數(shù)
ZGC回收機預(yù)計在jdk11支持碾盟,ZGC目前僅適用于Linux / x64?。和G1開啟很像技竟,用下面參數(shù)即可開啟:
-XX:+UnlockExperimentalVMOptions -XX:+UseZGC
原文鏈接:https://blog.csdn.net/CrankZ/article/details/86009279