收集器
- Serial收集器
單線程的收集器(只會(huì)使用一個(gè)CPU或一條收集線程去完成垃圾收集工作,進(jìn)行垃圾收集時(shí),必須暫停其他所有的工作線程,直到它收集結(jié)束响逢。)
虛擬機(jī)運(yùn)行在<code>Client</code>模式下的默認(rèn)新生代收集器。與其他收集器的單線程比更加簡單高效棕孙。
- ParNew收集器
Serial收集器的多線程版本
運(yùn)行在<code>Server</code>模式下的虛擬機(jī)中首選的新生代收集器龄句。其中一個(gè)與性能無關(guān)但很重要的原因是回论,除了Serial收集器外,目前只有它能與CMS收集器配合工作分歇。
- Parallel Scavenge收集器
它的關(guān)注點(diǎn)與其他收集器不同傀蓉,CMS等收集器的關(guān)注點(diǎn)是盡可能縮短垃圾收集時(shí)用戶線程停頓時(shí)間,而Parallel Scavenge收集器的目標(biāo)則是達(dá)到一個(gè)可控制的吞吐量职抡。
吞吐量=運(yùn)行用戶代碼時(shí)間/(運(yùn)行用戶代碼時(shí)間+垃圾收集時(shí)間)
-
Serial Old收集器
Serial收集器的老年代版本葬燎,單線程收集器,使用“標(biāo)記-整理”算法缚甩。
Parallel Old收集器
Parallel Scavenge收集器的老年代版本谱净,使用多線程,基于“標(biāo)記-整理”算法擅威。(JDK1.6中才開始提供)
- CMS收集器(Concurrent Mark Sweep)
以獲取最短回收停頓時(shí)間為目的的收集器壕探,基于“標(biāo)記-清除”算法。
耗時(shí)最長的并發(fā)標(biāo)記和并發(fā)清除過程收集器線程都可以與用戶線程一起工作郊丛。所以李请,CMS收集器的內(nèi)存回收過程是與用戶線程一起并發(fā)執(zhí)行的。
** 優(yōu)點(diǎn):**
- 并發(fā)收集
- 低停頓
缺點(diǎn):
- CMS收集器對(duì)CPU資源非常敏感厉熟。 在并發(fā)階段导盅,它雖然不會(huì)導(dǎo)致用戶線程停頓,但是會(huì)因?yàn)檎加靡徊糠志€程(或者說CPU資源)而導(dǎo)致應(yīng)用程序變慢揍瑟,總吞吐量會(huì)降低白翻。
- CMS收集器無法處理浮動(dòng)垃圾,可能出現(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無法再當(dāng)次收集中處理掉它們纪蜒,治好留待下一次GC時(shí)再清理掉。這部分垃圾就稱為“浮動(dòng)垃圾”此叠。因此,CMS不能像其他收集器那樣等到老年代幾乎完全被填滿再進(jìn)行手機(jī)随珠,CMS需要預(yù)留一部分空間灭袁。
- 由于CMS基于“標(biāo)記-清除”算法,意味著收集結(jié)束時(shí)會(huì)有大量空間碎片產(chǎn)生窗看。
- G1 收集器
當(dāng)今收集器技術(shù)發(fā)展的最前沿成果之一茸歧,G1是面向服務(wù)端應(yīng)用的垃圾收集器。
特點(diǎn)
- 并行與并發(fā):充分利用多CPU显沈、多核環(huán)境下的硬件優(yōu)勢软瞎,使用多個(gè)CPU(CPU或CPU核心)來縮短Stop-The-World停頓時(shí)間逢唤。部分其他收集器需要停頓Java線程執(zhí)行的GC動(dòng)作,G1仍然能通過并發(fā)方式讓Java程序繼續(xù)執(zhí)行涤浇。
- 分代收集:與其他收集器一樣鳖藕,分代概念在G1中依然得以保存。
- 空間整合:與CMS的“標(biāo)記-清理”算法不同只锭,G1從整體上看是基于<code>“標(biāo)記-整理”算法</code>實(shí)現(xiàn)的收集器著恩,從局部上看是基于<code>“復(fù)制”算法</code>實(shí)現(xiàn)的,這兩種算法意味著G1運(yùn)作期間不會(huì)產(chǎn)生內(nèi)存空間碎片蜻展。
- 可預(yù)測的停頓:這是G1相對(duì)于CMS的另一大優(yōu)勢喉誊,降低停頓時(shí)間是G1和CMS共同關(guān)注點(diǎn),但G1除了追求低停頓外纵顾,還能建立可預(yù)測的停頓時(shí)間模型伍茄,能讓使用者明確指定一個(gè)長度為M毫秒的時(shí)間片段內(nèi),消耗在垃圾收集上的時(shí)間不得從超出N毫秒施逾,這幾乎已經(jīng)是實(shí)時(shí)Java的垃圾收集器的特征了敷矫。
回收算法
-
標(biāo)記 - 清除
分為“標(biāo)記”和“清除”兩個(gè)階段,首先標(biāo)記出所有需要回收的對(duì)象音念,在標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象沪饺。
缺點(diǎn):
- 標(biāo)記和清除兩個(gè)過程效率不高
- 標(biāo)記清除后產(chǎn)生大量不連續(xù)的內(nèi)存碎片。
-
標(biāo)記 - 整理
讓所有存活對(duì)象向一端移動(dòng)闷愤。
- 復(fù)制算法
將內(nèi)存分為兩部分整葡,每次使用其中一塊,當(dāng)這塊內(nèi)存用完讥脐,就將還存活的對(duì)象復(fù)制到另一塊上面遭居。
缺點(diǎn):
- 浪費(fèi)一半內(nèi)存(改進(jìn)的方法是將新生代分為Eden、From Survivor旬渠、To Survivor俱萍。)
-
分代收集算法
把對(duì)象按照壽命長短進(jìn)行分組,分為新生代和老年代告丢,然后根據(jù)各個(gè)年代的特點(diǎn)采用最適當(dāng)?shù)氖占惴ㄇ鼓ⅲ谛律捎脧?fù)制算法,在老年代采用“標(biāo)記-清除”或者“標(biāo)記-整理”算法岖免。
搜索算法
引用計(jì)數(shù)算法(已廢棄)
給對(duì)象添加一個(gè)引用計(jì)數(shù)器岳颇,每當(dāng)有一個(gè)地方引用它時(shí),計(jì)數(shù)器+1颅湘,引用失效計(jì)數(shù)器-1话侧;任何時(shí)候計(jì)數(shù)器為0的對(duì)象就是不可能再被使用。這有個(gè)問題是闯参,兩個(gè)對(duì)象相互引用導(dǎo)致兩個(gè)對(duì)象都無法被回收瞻鹏。可達(dá)性分析算法
通過一系列的GC Roots對(duì)象作為起點(diǎn)悲立,從這些節(jié)點(diǎn)開始向下搜索。搜索所走過的路稱為引用鏈新博。當(dāng)一個(gè)對(duì)象到GC Roots沒有任何引用鏈相連時(shí)薪夕,則證明此對(duì)象不可用。
可作為GC Root的對(duì)象有:
- 虛擬機(jī)棧(棧幀的本地變量表)中引用的對(duì)象
- 方法區(qū)中類靜態(tài)屬性引用的對(duì)象
- 方法區(qū)中常量引用的對(duì)象
- 本地方法棧中JNI引用對(duì)象
即使在可達(dá)性分析中不可達(dá)的對(duì)象叭披,也并非是“非死不可”寥殖,這時(shí)候他們暫時(shí)處于“緩刑”階段。要真正宣告一個(gè)對(duì)象死亡涩蜘,需要經(jīng)歷兩個(gè)階段:
1)如果對(duì)象在進(jìn)行可達(dá)性分析后發(fā)現(xiàn)沒有與GC Roots相連接的引用鏈嚼贡,那它會(huì)被第一次標(biāo)記并且進(jìn)行一次篩選,篩選的條件是此對(duì)象是否有必要執(zhí)行finalize()方法同诫。當(dāng)對(duì)象沒有覆蓋finalize()方法粤策,或者finalize()方法已經(jīng)被虛擬機(jī)調(diào)用過,虛擬機(jī)將這兩種情況都視為“沒有必要執(zhí)行”误窖。
2)如果這個(gè)對(duì)象唄判斷為有必要執(zhí)行finalize()方法叮盘。那么這個(gè)對(duì)象會(huì)被放到一個(gè)F-Queue隊(duì)列中,并在稍后由一個(gè)虛擬機(jī)自動(dòng)建立的霹俺、優(yōu)先級(jí)低的Finalizer線程去執(zhí)行它柔吼,這里的“執(zhí)行”是指虛擬機(jī)會(huì)觸發(fā)這個(gè)方法,但并不承諾等待它運(yùn)行結(jié)束丙唧。這是為了防止finalize()方法執(zhí)行緩慢使得F-Queue隊(duì)列其他對(duì)象永久等待愈魏。
因此,對(duì)象可以在finalize()方法里把自己賦值給一個(gè)變量想际,以達(dá)到“自救”的目的培漏,但是這樣的“自救”只能用一次(虛擬機(jī)只會(huì)調(diào)用一次finalize()方法)。