《深入理解java虛擬機(jī)》筆記(二)----垃圾回收機(jī)制

1.內(nèi)存回收

java的運(yùn)行時(shí)數(shù)據(jù)區(qū)分為方法區(qū)、堆、虛擬機(jī)棧、本地方法棧和程序計(jì)數(shù)器,內(nèi)存回收關(guān)注的區(qū)域是java堆和方法區(qū),回收的對(duì)象是已經(jīng)"死去"的對(duì)象。

2.判斷對(duì)象的死亡

引用計(jì)數(shù)法

給對(duì)象添加一個(gè)引用計(jì)數(shù)器,有地方引用他,計(jì)數(shù)器加一,引用失效,計(jì)數(shù)器減一。計(jì)數(shù)器為0的對(duì)象判斷為死亡的對(duì)象。但是java中沒有采用引用計(jì)數(shù)法管理內(nèi)存,理由是它很難解決對(duì)象循環(huán)引用的問題

可達(dá)性分析算法

java、C#等語言采用可達(dá)性分析算法來判斷對(duì)象是否存活。具體做法是,通過一系列稱為"GC Roots"對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)開始向下搜索,搜索所走過的路徑稱為引用鏈,當(dāng)一個(gè)對(duì)象到"GC Roots"沒有引用鏈相連,就證明這個(gè)對(duì)象是不可達(dá)的。

java 引用

java希望描述這樣一類對(duì)象:當(dāng)內(nèi)存空間還足夠的時(shí)候,能保留在內(nèi)存中;如果內(nèi)存空間在進(jìn)行垃圾回收后還是非常緊張,則可以拋棄這些對(duì)象。(例如WeakHashMap中的entry)
JDK1.2后對(duì)引用進(jìn)行了擴(kuò)充,分為

  • 強(qiáng)引用
    類似Object obj = new Object,只要強(qiáng)引用還存在,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。
  • 軟引用
    軟引用關(guān)聯(lián)著的對(duì)象,在系統(tǒng)即將拋出內(nèi)存溢出異常之前,會(huì)將這些對(duì)象進(jìn)行第二次回收,如果這次回收后還沒有足夠的內(nèi)存才會(huì)拋出內(nèi)存溢出異常。(SoftReference類)
  • 弱引用
    強(qiáng)度比軟引用更弱,被弱引用關(guān)聯(lián)的對(duì)象,只能生存到下一次垃圾收集發(fā)生之前。當(dāng)垃圾收集器工作的時(shí)候,無論當(dāng)前內(nèi)存是否足夠,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象。(WeakReference類)
  • 虛引用
    最弱的引用關(guān)系,無法通過虛引用來取得一個(gè)對(duì)象實(shí)例。虛引用的唯一目的就是在這個(gè)對(duì)象被收集器回收的時(shí)候收到一個(gè)系統(tǒng)通知。
對(duì)象的finalize()方法

使用可達(dá)性分析算法中的不可達(dá)對(duì)象不會(huì)立刻被回收,分兩步:

  • 若對(duì)象分析不可達(dá),則對(duì)他進(jìn)行第一次標(biāo)記并進(jìn)行篩選,篩選的根據(jù)對(duì)象是否需要執(zhí)行finalize()方法。finalize()方法只會(huì)被執(zhí)行一次(如果能重復(fù)執(zhí)行那么這個(gè)對(duì)象可能永遠(yuǎn)無法回收)。如果沒有必要執(zhí)行finalize方法,會(huì)直接回收。
  • 如果需要執(zhí)行finalize方法,那么會(huì)對(duì)這些對(duì)象進(jìn)行第二次標(biāo)記,如果在finalize()方法中建立有效引用完成自救,那么會(huì)對(duì)他進(jìn)行第二次標(biāo)記并將它移出即將回收的集合。
方法區(qū)的回收

方法區(qū)垃圾收集的效率遠(yuǎn)低于堆,主要回收兩部分內(nèi)容:

  • 廢棄常量
    和java堆中對(duì)象回收類似,主要包括常量池中的類(接口)、方法、字段的符號(hào)引用。
  • 無用的類
    判斷類是無用的類條件比較苛刻,需要滿足下面三個(gè)條件:
    a. 該類所有實(shí)例被回收
    b.加載該類的ClassLoader已經(jīng)被回收
    c.該類對(duì)應(yīng)的java.lang.Class沒有在任何地方引用

3.垃圾收集算法

標(biāo)記-清除算法

標(biāo)記出需要回收的對(duì)象,標(biāo)記完成后統(tǒng)一回收所有被標(biāo)記的對(duì)象。CMS垃圾收集器就是采用這種算法。
優(yōu)勢(shì):
最基礎(chǔ)算法。
劣勢(shì):
標(biāo)記、清除兩個(gè)過程效率都不高;會(huì)產(chǎn)生空間碎片。

復(fù)制算法

解決了標(biāo)記-清除算法中的空間碎片問題。因?yàn)樾律袑?duì)象存活對(duì)象一般很少,可將內(nèi)存分為一份較大的Eden區(qū)域,兩份較小的Survivor區(qū)域,每次使用一個(gè)Eden和survivor區(qū)域,進(jìn)行垃圾回收的時(shí)候?qū)⑦@兩個(gè)區(qū)域的存活對(duì)象復(fù)制到另一個(gè)未使用的survivor區(qū)域上。如果survivor區(qū)域空間不夠,就會(huì)使用老年代進(jìn)行分配擔(dān)保。
優(yōu)勢(shì):
適合對(duì)象存活率低的新生代,沒有空間碎片。
劣勢(shì):
如果對(duì)象存活率高,那么復(fù)制操作的開銷會(huì)很大;會(huì)造成部分內(nèi)存空間浪費(fèi)。

標(biāo)記-整理算法

適用于老年代的算法,就是在標(biāo)記-清除算法的基礎(chǔ)上進(jìn)行了空間整理,解決了空間碎片問題。
優(yōu)勢(shì):
解決了空間碎片問題
劣勢(shì):
移動(dòng)對(duì)象也需要開銷

分代收集算法

當(dāng)前商用虛擬機(jī)都采用分代收集算法,將內(nèi)存分為兩個(gè)年代:

  • 新生代
    對(duì)象存活率較低的區(qū)域,適合復(fù)制算法
  • 老年代
    是新生代的分配擔(dān)保,對(duì)象存活率較高的區(qū)域,適合標(biāo)記-整理、標(biāo)記-清除算法。

4.Stop The world 問題

問題描述

在進(jìn)行可達(dá)性分析的過程中,可能會(huì)出現(xiàn)引用關(guān)系不斷變化的情況,為了避免這個(gè)情況,需要停頓所有的進(jìn)程再進(jìn)行GC。

HotSpot算法實(shí)現(xiàn)

在GC Roots枚舉的時(shí)候,使用OopMap數(shù)據(jù)結(jié)構(gòu)來得知哪些地方存在引用,用來快速準(zhǔn)確地完成根節(jié)點(diǎn)枚舉。
為了避免OopMap空間開銷過大,設(shè)立安全點(diǎn),只有線程運(yùn)行到安全點(diǎn)才會(huì)發(fā)生GC。
安全點(diǎn)又帶來了新的問題,如果線程停止就無法運(yùn)行到安全點(diǎn)。設(shè)立安全區(qū)域,線程在安全區(qū)域的時(shí)候,GC可以不用管這個(gè)線程。線程在出安全區(qū)域的時(shí)候,要等這次GC完成。

垃圾收集器

主要的新生代和老年代收集器如圖

image.png

CMS收集器
特點(diǎn)是并發(fā)收集,低停頓,是非常優(yōu)秀的老年代收集器,使用標(biāo)記-清除算法。由于停頓時(shí)間短,常用于互聯(lián)網(wǎng)服務(wù)器上。收集過程如下:
image.png

總結(jié)

為什么要進(jìn)行內(nèi)存回收?回收發(fā)生在哪里?回收哪些對(duì)象?回收算法?實(shí)際應(yīng)用?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容