本文章內(nèi)容基于《深入了解Java虛擬機》第二版搏色,對里面知識點進行總結(jié),JDK主要是1.6和1.7。
以下內(nèi)容圍繞HotSpot虛擬機的各種垃圾收集起實現(xiàn)狐赡。
目前沒有一個最好的收集器,都是針對不同區(qū)域的特性實現(xiàn)最好垃圾收集方法
Serial收集器
單線程的收集器(JDK1.3之前新生代收集器唯一選擇)
注意:單線程不是表示使用單個CPU或一個收集線程疟丙,而是進行垃圾收集颖侄,必須暫停其他所有工作線程
后續(xù)JDK不斷更新,目前只能不斷縮短暫停時間享郊,無法完全消除(排除RTSJ的收集器)
應(yīng)用范圍:目前應(yīng)用虛擬機運行在Client模式下的新生代收集器览祖。
優(yōu)點:簡單而高效(與其他收集器的單線程對比)
原因:
1、單CPU環(huán)境炊琉,Serial收集器沒有線程交互的開銷
2展蒂、用戶的桌面應(yīng)用場景,虛擬機管的內(nèi)容一般不大苔咪,暫停時間可以控制到接受范圍锰悼。
ParNew收集器
ParNew為Serial的多線程版本,其他與Serial完全一樣
應(yīng)用范圍:運行于Server模式的虛擬機首先新生代收集器
原因:
1悼泌、只有Serial與PerNew能與CMS收集配合工作(CMS收集器是優(yōu)秀并發(fā)收集器松捉,實現(xiàn)垃圾線程和用戶線程基本上同時工作;CMS作為老年代的收集器)
Parallel Scavenge收集器
該收集器是新生代收集器馆里,使用復(fù)制算法隘世,且是多線程
特點:其他收集器都為縮短暫停用戶線程的時間,該收集器目標則是達到一個可控的吞吐量鸠踪。
吞吐量 = 運行用戶代碼時間 / ( 運行用戶代碼時間 + 垃圾收集時間)
對比:
1丙者、暫停時間越短:適合需要與用戶交互的程序,提交響應(yīng)速度营密。
2械媒、吞吐量高:高效率使用CPU,盡快完成程序的運算任務(wù),適合后臺運算不需要太多交互的任務(wù)纷捞。
注意:GC暫停時間縮短一般通過犧牲吞吐量和空間來實現(xiàn)痢虹。
Serial Old收集器
Serial收集器的老年代版本,單線程收集器主儡,使用標記-整理算法奖唯,Client模式下使用。
用途:
1糜值、與Parallel Scavenge收集器搭配使用
2丰捷、作為CMS收集器的后備預(yù)案。
Parallel Old收集器
是Parallel Scavenge收集器的老年代版本寂汇,多線程病往、標記-整理算法。
用途:
Parallel Scavenge收集器無法與CMS收集器配合骄瓣,Serial Old單線程在服務(wù)端性能不足停巷。推出Parallel Old收集器配合Parallel Scavenge收集器在服務(wù)端提性能。
CMS收集器
是一種一獲取最短回收暫停時間為目標的收集器累贤,目前廣泛應(yīng)用互聯(lián)網(wǎng)站或B/S系統(tǒng)的服務(wù)端叠穆。基于標記-清除算法
分為四個階段:
1臼膏、初始標記:標記GC Roots能直接關(guān)聯(lián)的對象硼被;暫停用戶線程
2、并發(fā)標記:進行GC Roots Tracing過程
3渗磅、重新標記:修正并發(fā)標記期間因用戶程序運行導致標記變動嚷硫;暫停用戶線程
4、并發(fā)清除:多線程清除無用對象始鱼。
缺點:
1仔掸、CMS收集器對CPU資源非常敏感,占用一部分CPU資源医清,導致應(yīng)用程序變慢起暮,總吞吐量降低。(CPU數(shù)量越少会烙,CMS性能變低)
2负懦、CMS收集器無法處理浮動垃圾。并發(fā)清除過程中柏腻,用戶線程還會生產(chǎn)新的垃圾纸厉,需要等到下次GC才能清除。
而且運行過程還要給用戶線程預(yù)留內(nèi)存空間五嫂,當出現(xiàn)預(yù)留的空間無法滿足程序需求颗品,則要臨時啟動Serial Old收集器邏輯肯尺,
3、采用標記-清除算法會出現(xiàn)很多碎片躯枢,不足是會進行 full GC操作
G1收集器
面對服務(wù)端應(yīng)用的垃圾收集器则吟。替換CMS收集器
特點:
1、并行與并發(fā):充分利用多CPU锄蹂、多核環(huán)境的優(yōu)勢
2逾滥、分代收集:G1不需要與其他收集器配合,獨立管理整個GC堆
3败匹、空間整合:整體為標記整理算法,局部為復(fù)制算法(兩個region之間)
4讥巡、可預(yù)測的停頓:建立可預(yù)測的停頓時間模型掀亩,能夠讓使用者明確指定的一個長度為M毫秒的時間片段內(nèi)。垃圾收集回收不超過N毫秒欢顷。
內(nèi)存分配:
G1收集起將整個Java堆分為多個大小相等的獨立區(qū)域(新生代和老生代不在物理隔離槽棍,是一部分region的集合)
建立可預(yù)測的停頓時間模型:
G1跟蹤各個region的垃圾堆積的價值大小(收集獲取空間以及回收所需時間)抬驴,后臺維護一個優(yōu)先列表炼七,優(yōu)先回收價值最大的region。
問題:單獨region內(nèi)的對象會被其他region對象引用布持,難道還是要整個Java堆掃描豌拙?
答:使用Remembered Set來避免全表掃描,每個region都有一個對應(yīng)的Remembered Set题暖。為了登記引用對象被其他region對象引用的信息按傅。
進行內(nèi)存回收時,會引入Remembered Set保證不對全堆掃描胧卤。
如果不包含維護Remembered Set唯绍,步驟為
1、初始標記:標記GC Roots能直接關(guān)聯(lián)的對象枝誊;暫停用戶線程
2况芒、并發(fā)標記:進行GC Roots Tracing過程
3、最終標記:修正并發(fā)標記期間因用戶程序運行導致標記變動叶撒;暫停用戶線程
該階段會維護Remembered Set
4绝骚、篩選回收:多線程清除無用對象。
內(nèi)存分配與回收策略總結(jié)
對象內(nèi)存分配的大方向就是堆上分配痊乾。
獨享主要分配在新生代的Eden區(qū)皮壁。如果啟動本地線程分配緩沖,將按照線程優(yōu)先在TLAB上分配哪审。少數(shù)情況也可能直接分配在老年代蛾魄。
對象優(yōu)先分配在Eden分配
大多數(shù)情況之下,對象在新生代Eden區(qū)中分配,當Eden區(qū)沒有足夠空間滴须,虛擬機會進行一個Minor GC舌狗。
Minor GC與Full GC區(qū)別
新生代(Minor GC):新生代的垃圾回收,非常頻繁扔水,一般回收速度較快痛侍。
老年代(Major GC/Full GC):老年代的垃圾回收,出現(xiàn)Major GC之前一般至少出現(xiàn)一次Minor GC魔市,Minor GC速度一般比Minor GC慢10倍以上主届。
老年代
大對象直接進入老年代:
大對象是指需要大量連續(xù)的內(nèi)存空間對象(長字符串以及數(shù)組)。
長期存活的對象將進入老年代:
每個對象都會定義一個年齡(Age)計算器待德,每次Minor GC之后還存在君丁,則年齡+1。隨著年齡增加到一定程度(默認為15)就晉升到老年代将宪。
動態(tài)對象年齡判定:
虛擬機不是一直要求年齡必須達到指定年齡才能進入老年代绘闷。如果Survivor空間中相同年齡所有對象大小總和大于survivor空間的一半,年齡大于或則等于該年齡的對象就可以直接進入老年代较坛。
空間分配擔保:
Minor GC之前印蔗,虛擬機會先檢查老年代最大可用連續(xù)空間是否大于新生代所有對象總空間,如果條件成立丑勤,那么Minor GC可以確保是安全华嘹。
如果條件不成立,會檢查是否允許擔保失斎贩狻:
如果允許:繼續(xù)檢查老年代最大可用的連續(xù)空間是否大于歷次晉升到老年代對象的平均大小除呵。
如果大于:嘗試進行一次Minor GC(該GC存在風險)
如果小于或則不允許冒險:則進行一次Full GC
何為冒險?
新生代使用復(fù)制算法爪喘,其中一個survivor空間作為輪換備份颜曾,如果出現(xiàn)大量對象在Minor GC之后存在,則需要老年代進行分配擔保秉剑,把survivor無法容納的對象直接進入老年代泛豪。冒險在于老年代剩余空間是否足夠。