垃圾回收機制:
什么時候:
什么時候開啟垃圾回收(觸發(fā)GC的條件),GC觸發(fā)的條件有兩種:①抬虽、程序調(diào)用System.gc時可以觸發(fā);②属桦、系統(tǒng)自身判斷GC的依據(jù):根據(jù)Eden區(qū)和From Space區(qū)的內(nèi)存大小來決定匠题。當(dāng)內(nèi)存大小不足時缔赠,則會啟動GC線程并停止應(yīng)用線程。
對什么東西:
GC操作的對象分為:通過可達(dá)性分析法無法搜索到的對象和可以搜索到的對象褂微,對于搜索不到的對象進(jìn)行標(biāo)記
做了什么:
對于可以搜索到的對象進(jìn)行復(fù)制操作功蜓,對于搜索不到的對象,調(diào)用finalize()方法進(jìn)行釋放宠蚂。
常見的垃圾回收算法:
-
引用計數(shù):
- 每個對象有一個引用計數(shù)屬性式撼,新增一個引用時計數(shù)加1,引用釋放時計數(shù)減1肥矢,計數(shù)為0時可用回收端衰。此方法簡單,無法解決對象相互循環(huán)引用的問題甘改,且每次對對象復(fù)制時均要維護(hù)引用計數(shù)器旅东,且計數(shù)器本身也有一定的消耗。
- 每個對象有一個引用計數(shù)屬性式撼,新增一個引用時計數(shù)加1,引用釋放時計數(shù)減1肥矢,計數(shù)為0時可用回收端衰。此方法簡單,無法解決對象相互循環(huán)引用的問題甘改,且每次對對象復(fù)制時均要維護(hù)引用計數(shù)器旅东,且計數(shù)器本身也有一定的消耗。
復(fù)制算法:
堆內(nèi)存:
- 新生代:新生代劃分為Eden(伊甸園)與SurvivorFrom與SurvivorTo
-
老年代:老年代的空間里只有老年代
- 1十艾、首先抵代,當(dāng)Eden區(qū)滿的時候回觸發(fā)第一次GC,把還活著的對象拷貝到SurvivorFrom區(qū)忘嫉,當(dāng)Eden區(qū)再次觸發(fā)GC的時候會掃描Eden區(qū)和From區(qū)域荤牍,對這兩個區(qū)域進(jìn)行垃圾回收案腺,經(jīng)過這次回收后還存活著的對象,則直接復(fù)制到To區(qū)域(如果有對象的年齡已經(jīng)達(dá)到了老年的標(biāo)準(zhǔn)康吵,則賦值到老年代區(qū))劈榨,同時把這些對象的年齡 + 1
- 2、然后晦嵌,情況Eden和SurvivoFrom中的對象同辣,也即復(fù)制之后有交換,誰空誰是To
- 3惭载、SurvivorTo和SurvivorFrom互換
最后旱函,SUrvivoTo和SurvivorFrom互換,原SurvivorTo成為下一次GC時的SurvivorFrom區(qū)描滔。部分對象會在From和To區(qū)域中復(fù)制來復(fù)制去棒妨,如此交換15次(由JVM參數(shù)MaxTenuringThreshold決定,這個參數(shù)默認(rèn)是15)含长,最終如果還是存活券腔,就存入老年代
優(yōu)點:
在存活對象不多的情況下,性能高拘泞,能解決內(nèi)存碎片和java垃圾回收算法之-標(biāo)記清除中導(dǎo)致的引用更新問題颅眶。
缺點:
會造成一部分的內(nèi)存浪費。不過可以根據(jù)實際情況田弥,將內(nèi)存塊大小比例適當(dāng)調(diào)整涛酗;
如果存活對象的數(shù)量比較大,coping的性能會變得很差
-
標(biāo)記清除算法
標(biāo)記清除.png
標(biāo)記清除算法分為兩個階段:標(biāo)記和清除偷厦。
它的做法是當(dāng)堆中的有效內(nèi)存空間(available memory)被耗盡的時候商叹,就會讓整個程序stop然后進(jìn)行標(biāo)記再清除
標(biāo)記:標(biāo)記的過程其實就是,遍歷所有的GC Roots只泼,然后將所有的GC Roots可達(dá)的對象標(biāo)記為存活的對象剖笙。
清除:清除的過程將遍歷堆中所有的對象中沒有標(biāo)記的對象全部清除掉
缺點:
1、它的缺點就是效率比較低(遞歸與全堆對象遍歷)请唱,而且在進(jìn)行GC的時候弥咪,需要停止應(yīng)用程序。
2十绑、這種方式清理出來的空閑內(nèi)存是不連續(xù)的聚至。我們的死亡對象都是隨機的出現(xiàn)在內(nèi)存的各個角落,把它們都清除之后本橙,內(nèi)存的布局自然會亂七八糟扳躬,為了應(yīng)付這一點,JVM就不得不維持一個內(nèi)存的空閑列表,這又是一個開銷贷币。而且在分配數(shù)組對象的击胜,尋找連續(xù)的內(nèi)存不好找 標(biāo)記整理
分為標(biāo)記和整理兩個階段:首先標(biāo)記出所有需要回收的對象,讓所有存活的對象都向一端移動役纹,然后直接清理掉邊界意外的內(nèi)存偶摔。
優(yōu)點:不會產(chǎn)生空間碎片,但是整理會需要一點時間
地方:適合老年代進(jìn)行垃圾收集促脉,parallel Old(針對parallel scanvange gc的) gc和Serial old收集器就是采用該算法進(jìn)行回收的啰挪。-
分代收集算法
目前商用虛擬機都使用“分代收集算法”,所謂分代就是根據(jù)對象的生命周期把內(nèi)存分為幾塊嘲叔,一般把Java堆中分為新生代和老年代,這樣就可以根據(jù)對象的“年齡”選擇合適的垃圾回收算法抽活。- 新生代:“朝生夕死”硫戈,存活率低,使用復(fù)制算法下硕。
- 老年代:存活率較高丁逝,使用“標(biāo)記-清除”算法或者“標(biāo)記-整理”算法。
垃圾收集器
如果說收集算法是內(nèi)存回收的方法論梭姓,垃圾收集器就是內(nèi)存回收的具體實現(xiàn)
Serial收集器
串行收集器是最古老霜幼,最穩(wěn)定以及效率高的收集器,可能會產(chǎn)生較長的停頓誉尖,只是用一個線程去回收罪既。新生代、老年代使用串行回收铡恕;新生代復(fù)制算法琢感、老年代標(biāo)記 - 壓縮;垃圾收集的過程中會Stop The World(服務(wù)暫停)
參數(shù)控制: -XX:+UseSerialGC 串行收集器
-
ParNew 收集器 ParNew收集器其實就是Serial收集器的多線程版本探熔。新生代并行驹针,老年代串行;新生代復(fù)制算法诀艰、老年代標(biāo)記-壓縮
參數(shù)控制:
-XX:+UseParNewGC ParNew收集器
-XX:ParallelGCThreads 限制線程數(shù)量
image
Parallel收集器
Parallel Scavenge收集器類似ParNew收集器,Parallel收集器更關(guān)注系統(tǒng)的吞吐量∷酪Γ可以通過參數(shù)來打開自適應(yīng)調(diào)節(jié)策略爽丹,虛擬機會根據(jù)當(dāng)前系統(tǒng)的運行情況收集性能監(jiān)控信息,動態(tài)調(diào)整這些參數(shù)以提供最合適的停頓時間或最大的吞吐量绿满;也可以通過參數(shù)控制GC的時間不大于多少毫秒或者比例撤防;新生代復(fù)制算法、老年代標(biāo)記-壓縮
參數(shù)控制: -XX:+UseParallelGC 使用Parallel收集器+ 老年代串行
Parallel Old 收集器
Parallel Old是Parallel Scavenge收集器的老年代版本,使用多線程和“標(biāo)記-整理”算法寄月。這個收集器是在JDK 1.6中才開始提供
參數(shù)控制: -XX:+UseParallelOldGC 使用Parallel收集器+ 老年代并行
CMS收集器
CMS(Concurrent Mark Sweep)收集器是一種以獲取最短回收停頓時間為目標(biāo)的收集器辜膝。目前很大一部分的Java應(yīng)用都集中在互聯(lián)網(wǎng)站或B/S系統(tǒng)的服務(wù)端上,這類應(yīng)用尤其重視服務(wù)的響應(yīng)速度漾肮,希望系統(tǒng)停頓時間最短厂抖,以給用戶帶來較好的體驗。
從名字(包含“Mark Sweep”)上就可以看出CMS收集器是基于“標(biāo)記-清除”算法實現(xiàn)的克懊,它的運作過程相對于前面幾種收集器來說要更復(fù)雜一些忱辅,整個過程分為4個步驟,包括:
初始標(biāo)記(CMS initial mark)
并發(fā)標(biāo)記(CMS concurrent mark)
重新標(biāo)記(CMS remark)
并發(fā)清除(CMS concurrent sweep)
其中初始標(biāo)記谭溉、重新標(biāo)記這兩個步驟仍然需要“Stop The World”墙懂。初始標(biāo)記僅僅只是標(biāo)記一下GC Roots能直接關(guān)聯(lián)到的對象,速度很快扮念,并發(fā)標(biāo)記階段就是進(jìn)行GC Roots Tracing的過程损搬,而重新標(biāo)記階段則是為了修正并發(fā)標(biāo)記期間,因用戶程序繼續(xù)運作而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分對象的標(biāo)記記錄柜与,這個階段的停頓時間一般會比初始標(biāo)記階段稍長一些巧勤,但遠(yuǎn)比并發(fā)標(biāo)記的時間短。
由于整個過程中耗時最長的并發(fā)標(biāo)記和并發(fā)清除過程中弄匕,收集器線程都可以與用戶線程一起工作颅悉,所以總體上來說,CMS收集器的內(nèi)存回收過程是與用戶線程一起并發(fā)地執(zhí)行迁匠。老年代收集器(新生代使用ParNew)
優(yōu)點: 并發(fā)收集剩瓶、低停頓
缺點: 產(chǎn)生大量空間碎片、并發(fā)階段會降低吞吐量
參數(shù)控制:
-XX:+UseConcMarkSweepGC 使用CMS收集器
-XX:+ UseCMSCompactAtFullCollection Full GC后城丧,進(jìn)行一次碎片整理儒搭;整理過程是獨占的,會引起停頓時間變長
-XX:+CMSFullGCsBeforeCompaction 設(shè)置進(jìn)行幾次Full GC后芙贫,進(jìn)行一次碎片整理
-XX:ParallelCMSThreads 設(shè)定CMS的線程數(shù)量(一般情況約等于可用CPU數(shù)量)
G1收集器
GcRoot
所謂"GC roots" 或者說tracing GC的"根集合"就是一組必須活躍的引用搂鲫。
基本思路就是通過一系列名為"GC Roots"的對象作為起始點,從這個被稱為GC Roots的對象開始向下搜索磺平,如果一個對象到GC Roots沒有任何引用鏈相連時魂仍,則說明此對象不可用。也即給定一個集合的引用作為根出發(fā)拣挪,通過引用關(guān)系遍歷對象圖擦酌,能被遍歷到的(可到達(dá)的)對象就被判定為存活;沒有被遍歷到的就自然被判定為死亡
哪些可以作為GC Roots的對象:
虛擬機棧(棧幀中的局部變量區(qū)菠劝,也叫做局部變量表)中引用的對象
方法區(qū)中的類靜態(tài)屬性引用的對象赊舶。
方法區(qū)中常量引用的對象
本地方法棧中JNI(Native方法)引用的對象