JVM系列二:垃圾回收
什么時(shí)候回收對象
引用計(jì)數(shù)法?
1、原理:為對象添加一個(gè)引用計(jì)數(shù)器,當(dāng)對象增加一個(gè)引用時(shí)計(jì)數(shù)器加 1,引用失效時(shí)計(jì)數(shù)器減 1。引用計(jì)數(shù)為 0 的對象可被回收。
2、缺點(diǎn):無法解決循環(huán)引用問題
可達(dá)性分析
1、原理:以 GC Roots 為起始點(diǎn)進(jìn)行搜索,可達(dá)的對象都是存活的,不可達(dá)的對象可被回收。
2、可作為GC Root的對象:
- 虛擬機(jī)棧中局部變量表中引用的對象
- 本地方法棧中 JNI 中引用的對象
- 方法區(qū)中類靜態(tài)屬性引用的對象
- 方法區(qū)中的常量引用的對象
方法區(qū)回收
1、主要是對類的卸載和對常量池的回收,對于大量引用動(dòng)態(tài)代理和反射的場景下,類的卸載是具有重要意義的
2、類的卸載需滿足以下三個(gè)條件,但是就算三個(gè)條件都滿足也不一定就被卸載
- 該類所有的實(shí)例都已經(jīng)被回收,此時(shí)堆中不存在該類的任何實(shí)例。
- 加載該類的 ClassLoader 已經(jīng)被回收。
- 該類對應(yīng)的 Class 對象沒有在任何地方被引用,也就無法在任何地方通過反射訪問該類方法。
finalize方法
1、類似 C++ 的析構(gòu)函數(shù),用于關(guān)閉外部資源。但是 try-finally 等方式可以做得更好,并且該方法運(yùn)行代價(jià)很高,不確定性大,無法保證各個(gè)對象的調(diào)用順序,因此最好不要使用。
2、當(dāng)一個(gè)對象可被回收時(shí),如果需要執(zhí)行該對象的 finalize() 方法,那么就有可能在該方法中讓對象重新被引用,從而實(shí)現(xiàn)自救。
自救只能進(jìn)行一次,如果回收的對象之前調(diào)用了 finalize() 方法自救,后面回收時(shí)不會(huì)再調(diào)用該方法
四種引用
不管是引用計(jì)數(shù)法還是可達(dá)性分析,引用的判斷與計(jì)數(shù)都是很重要的
強(qiáng)引用
1、特點(diǎn):不會(huì)被回收
2、構(gòu)造方式:new
?1?Object object = new Object();?
軟應(yīng)用
1、特點(diǎn):只有在內(nèi)存不夠的時(shí)候才會(huì)被回收
2、構(gòu)造方式:SoftReference
1 Object object = new Object(); 2 SoftReference<Object> sf = new SoftReference<Object>(object); 3 object = null;//使對象只能被軟引用關(guān)聯(lián)?
弱引用
1、特點(diǎn):下一次內(nèi)存回收的時(shí)候一定會(huì)被回收
2、構(gòu)造方式:WeakReference
1 Object object = new Object(); 2 WeakReference<Object> sf = new WeakReference<Object>(object); 3 object = null;?
虛引用
1、特點(diǎn):沒有辦法得到一個(gè)虛引用對象,設(shè)置它的唯一目的就是在系統(tǒng)回收它的時(shí)候得到一個(gè)通知
2、構(gòu)造方式:PhantomReference
1 Object object = new Object(); 2 PhantomReference<Object> sf = new PhantomReference<Object>(object); 3 object = null;?
垃圾收集算法
標(biāo)記-清除算法
1、過程
(1)標(biāo)記階段:程序會(huì)檢查每個(gè)對象是否為活動(dòng)對象,如果是活動(dòng)對象,則程序會(huì)在對象頭部打上標(biāo)記。
(2)清除階段:會(huì)進(jìn)行對象回收并取消標(biāo)志位,另外,還會(huì)判斷回收后的分塊與前一個(gè)空閑分塊是否連續(xù),若連續(xù),會(huì)合并這兩個(gè)分塊。
回收對象就是把對象作為分塊,連接到被稱為 “空閑鏈表” 的單向鏈表,之后進(jìn)行分配時(shí)只需要遍歷這個(gè)空閑鏈表,就可以找到分塊。
在分配時(shí),程序會(huì)搜索空閑鏈表尋找空間大于等于新對象大小 size 的塊 block。如果它找到的塊等于 size,會(huì)直接返回這個(gè)分塊;
如果找到的塊大于 size,會(huì)將塊分割成大小為 size 與 (block - size) 的兩部分,返回大小為 size 的分塊,并把大小為 (block - size) 的塊返回給空閑鏈表。
2、圖解
?
?
3、缺點(diǎn)
- 標(biāo)記和清除的過程效率都不高
- 可能產(chǎn)生大量內(nèi)存碎片
?
標(biāo)記-整理算法
1、過程
讓所有存活的對象都向一端移動(dòng),然后直接清理掉端邊界以外的內(nèi)存。
2、圖解
?
?
3、缺點(diǎn)
每次都要移動(dòng)存活的對象
?
復(fù)制算法
1、過程
將內(nèi)存劃分為大小相等的兩塊,每次只使用其中一塊,當(dāng)這一塊內(nèi)存用完了就將還存活的對象復(fù)制到另一塊上面,然后再把使用過的內(nèi)存空間進(jìn)行一次清理。
現(xiàn)在的商業(yè)虛擬機(jī)都采用這種收集算法回收新生代,但是并不是劃分為大小相等的兩塊,而是一塊較大的 Eden 空間和兩塊較小的 Survivor 空間,每次使用 Eden 和其中一塊 Survivor。在回收時(shí),將 Eden 和 Survivor 中還存活著的對象全部復(fù)制到另一塊 Survivor 上,最后清理 Eden 和使用過的那一塊 Survivor。
HotSpot 虛擬機(jī)的 Eden 和 Survivor 大小比例默認(rèn)為 8:1,保證了內(nèi)存的利用率達(dá)到 90%。如果每次回收有多于 10% 的對象存活,那么一塊 Survivor 就不夠用了,此時(shí)需要依賴于老年代進(jìn)行空間分配擔(dān)保,也就是借用老年代的空間存儲(chǔ)放不下的對象。
2、圖解
?
3、缺點(diǎn)
每次只能用到局部的內(nèi)存
?
分代收集算法
1、按照對象生存周期將內(nèi)存分為不同的區(qū)域主要分成新生代和老年代,不同的區(qū)域采取不同的收集算法
2、新生代:采取復(fù)制算法
? 老年代:采取標(biāo)記-清理算法或者標(biāo)記-整理算法
?
垃圾收集器
?
新生代收集器
Serial收集器
?
ParNew收集器
?
Parallel Scavenge收集器
?
與 ParNew 一樣是多線程收集器。
其它收集器目標(biāo)是盡可能縮短垃圾收集時(shí)用戶線程的停頓時(shí)間,而它的目標(biāo)是達(dá)到一個(gè)可控制的吞吐量,因此它被稱為“吞吐量優(yōu)先”收集器。這里的吞吐量指 CPU 用于運(yùn)行用戶程序的時(shí)間占總時(shí)間的比值。
?
老年代收集器
?
Serial Old收集器
?
Parallel Old收集器
?
CMS收集器
?
G1收集器
?
?
搭配關(guān)系
?
比較總結(jié)
?
| 收集器 | 收集算法 | 新生代/老年代 | 備注 |
| Serial | 復(fù)制算法 | 新生代 | |
| ParNew | 復(fù)制算法 | 新生代 | |
| Parallel Scavenge | 復(fù)制算法 | 新生代 | ? |
| Serial Old | 標(biāo)記-整理算法 | 老年代 | ? |
| Parallel Old | 標(biāo)記-整理算法 | 老年代 | |
| CMS | 標(biāo)記-清除算法 | 老年代 | ? |
| G1 | 標(biāo)記-整理算法 | 新生代+老年代 | ? |
轉(zhuǎn)載于:https://www.cnblogs.com/huanglf714/p/11027336.html
總結(jié)
以上是生活随笔為你收集整理的JVM系列二:垃圾回收的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2019春季学期进度报告(十六)
- 下一篇: oracle之4多行函数之分组函数