哪些內(nèi)存需要回收
什么時(shí)候回收
如何回收
垃圾回收線程是守護(hù)線程,平常到達(dá)安全點(diǎn)和安全區(qū)域時(shí)會(huì)回收,當(dāng)堆內(nèi)存占用到達(dá)上限時(shí)Full GC
3.1引用計(jì)數(shù)算法和可達(dá)性分析算法
3.1.1引用計(jì)數(shù)算法
在對(duì)象中添加一個(gè)引用計(jì)數(shù)器,每當(dāng)有一個(gè)引用它時(shí)計(jì)數(shù)器就加一;當(dāng)引用失效時(shí)計(jì)數(shù)器就減一;任何時(shí)刻計(jì)數(shù)器為零的對(duì)象就是不可能再被使用的;
缺點(diǎn):如果兩個(gè)對(duì)象相互引用不會(huì)被回收
3.1.2可達(dá)性分析算法
一般虛擬機(jī)采用的是這種方法
基本思路:通過(guò)一系列被稱為“GC Roots”的根對(duì)象作為起始節(jié)點(diǎn)集,從這些節(jié)點(diǎn)開(kāi)始根據(jù)引用關(guān)系向下搜索,搜索過(guò)程走過(guò)的路徑稱為“引用鏈”,如果某個(gè)對(duì)象到GC Root之間沒(méi)有任何引用鏈,代表對(duì)象不可達(dá),則證明此對(duì)象不會(huì)再被使用
GC Root 有(可以根據(jù)具體的場(chǎng)景指定,下邊的相當(dāng)于是全局回收時(shí)用到的):
虛擬機(jī)棧 中引用的對(duì)象
方法區(qū) 中類(lèi)靜態(tài)屬性引用的對(duì)象,常量引用的對(duì)象
虛擬機(jī)內(nèi)部的引用? Class對(duì)象中的一些異常對(duì)象 空指針,堆溢出
同步鎖持有的對(duì)象 synchronized
當(dāng)分代回收時(shí),是局部回收,就可以指定要回收的代為GC Root
強(qiáng)引用、軟引用、弱引用、虛引用
為了再次細(xì)化垃圾回收的時(shí)機(jī),又將已經(jīng)被引用的對(duì)象細(xì)分為這四種狀態(tài)
強(qiáng)引用:一般理解的引用 Object object = new Object();
軟引用:還有些用但非必須的對(duì)象,GC之后內(nèi)存還是不夠,會(huì)在內(nèi)存溢出之前對(duì)這些對(duì)象進(jìn)行二次回收
弱引用:表示只能生存到下次垃圾回收
虛引用:虛引用不會(huì)影響回收時(shí)間,只是會(huì)在回收時(shí)收到一個(gè)系統(tǒng)通知
3.2方法區(qū)的回收
方法區(qū)的回收性價(jià)比比較低,是否回收可以通過(guò)配置設(shè)置
回收條件:
1.類(lèi)所有的實(shí)例已經(jīng)被回收,包括所有的派生類(lèi)
2.這個(gè)類(lèi)的類(lèi)加載器已經(jīng)被回收,這種場(chǎng)景存在于OSGI JSP的重新加載
3.類(lèi)的Class對(duì)象沒(méi)有任何地方被引用
3.3垃圾回收算法
準(zhǔn)備工作:分代,堆分為年輕代和老年代(G1是將堆分為若干Region)
針對(duì)不同的分代采用不同的回收類(lèi)型
Minor GC(年輕代)? Major GC(老年代) Full GC(堆+方法區(qū))
不同的區(qū)域也可以采用不同的算法:標(biāo)記-復(fù)制、標(biāo)記-清除、標(biāo)記-整理
3.3.1標(biāo)記清除算法
標(biāo)記要清除的對(duì)象或者標(biāo)記不需要清除的對(duì)象,然后進(jìn)行清除
缺點(diǎn):
1.如果需要回收的對(duì)象過(guò)程,需要進(jìn)行大量的標(biāo)記清除動(dòng)作,執(zhí)行效率會(huì)降低
2.容易產(chǎn)生內(nèi)存碎片,內(nèi)存利用率低
“分區(qū)空閑鏈表” 表明現(xiàn)在的可用空間
3.3.2標(biāo)記復(fù)制算法
基本思想“半?yún)^(qū)復(fù)制”,將內(nèi)存安裝大小分為兩個(gè)相同的區(qū)域,每次只使用其中的一塊,當(dāng)這塊用完時(shí),將活著的對(duì)象復(fù)制到另一塊,再將原來(lái)的一塊清空。
實(shí)際使用中不按1:1的比例劃分,好比是9:1的比例,復(fù)制時(shí)第二塊就有可能裝不下就需要有其他內(nèi)存做為擔(dān)保,一般用老年代做擔(dān)保。
老年代沒(méi)有擔(dān)??臻g,就不方便采用這種算法
HotSpot對(duì)年輕代采用的是這種算法,將年輕代分為Eden和兩個(gè)Survivor
3.3.3標(biāo)記整理
標(biāo)記對(duì)象,將存活的對(duì)象移動(dòng)至內(nèi)存前端
缺點(diǎn):對(duì)象移動(dòng)時(shí)需要用戶程序停止即“Stop The World”
可以將標(biāo)記清除和標(biāo)記整理配合使用,當(dāng)內(nèi)存碎片影響內(nèi)存分配時(shí)使用一次標(biāo)記整理
3.4OopMap、安全點(diǎn)、安全區(qū)域
一旦觸發(fā)了垃圾回收,如何確定垃圾回收線程的執(zhí)行時(shí)間
Hotspot為了確定垃圾回收的時(shí)間引入了安全點(diǎn)和安全區(qū)域的概念,安全點(diǎn)和安全區(qū)域代表內(nèi)存區(qū)域沒(méi)有發(fā)生變化,這個(gè)時(shí)候能夠允許回收線程和用戶線程可以同時(shí)進(jìn)行
3.4.1用OopMap埋點(diǎn)? 這個(gè)重新看一下,尋找對(duì)象的引用關(guān)系應(yīng)該是內(nèi)存的角度
Hotspot在類(lèi)加載完成時(shí)用OoMap的數(shù)據(jù)結(jié)構(gòu)記錄了對(duì)象的引用關(guān)系,在編譯完的字節(jié)碼文件中有這種記錄的體現(xiàn),當(dāng)進(jìn)行GC時(shí)不需要從GC Roots開(kāi)始進(jìn)行查找
OopMap在字節(jié)碼文件表明從某個(gè)位置到某個(gè)位置引用了某個(gè)對(duì)象
3.4.2安全點(diǎn)
OopMap記錄的位置即為安全點(diǎn)
用戶線程到達(dá)安全點(diǎn)之后會(huì)將自己掛起,等待GC線程執(zhí)行
安全點(diǎn):方法調(diào)用、循環(huán)跳轉(zhuǎn)、異常跳轉(zhuǎn)
3.4.3安全區(qū)域
某一段代碼片段之中,引用關(guān)系不會(huì)發(fā)生變化
用戶線程進(jìn)入安全區(qū)域之后會(huì)意識(shí)到自己進(jìn)入了安全區(qū)域,當(dāng)要出安全區(qū)域時(shí)先判斷GC操作是否完成如果沒(méi)有就會(huì)等待直到完成