Java虛擬機(jī)垃圾收集機(jī)制

垃圾收集機(jī)制

在虛擬機(jī)內(nèi)存模型中:

  1. 程序計(jì)數(shù)器辐赞,消耗內(nèi)存可以忽略不計(jì)
  2. 虛擬機(jī)棧部翘,在編譯期可知需要分配多少內(nèi)存空間,棧幀入棧分配空間响委,出椥滤迹回收內(nèi)存窖梁。
  3. 本地方法棧,與虛擬機(jī)椉星簦基本一致纵刘。
  4. Java堆,最大的內(nèi)存區(qū)域荸哟,對象幾乎在運(yùn)行時才分配內(nèi)存假哎,創(chuàng)建頻繁甚至需要同步分配,所以堆內(nèi)存自動回收機(jī)制特別重要鞍历。
  5. 方法區(qū)舵抹,同樣需要內(nèi)存回收。

本章了解整個垃圾收集機(jī)制

  1. 了解垃圾收集流程
  2. 重點(diǎn)掌握虛擬機(jī)垃圾收集算法:
    • 對象存活判定算法
    • 垃圾收集算法
  3. 虛擬機(jī)GC算法實(shí)現(xiàn)
  4. 垃圾收集器
  5. 對象在GC時如何分配

對象存活判定算法

什么時候發(fā)生GC

當(dāng)分配Java對象內(nèi)存時劣砍,Java堆內(nèi)存空間不夠掏父,且無法擴(kuò)展時,進(jìn)行一次GC

GC處理的是Java堆中的對象秆剪,哪些對象是需要回收的呢

這就需要對象存活判定算法赊淑,目前有兩種對象存活判定算法

  1. 引用計(jì)數(shù)法
  2. 可達(dá)性分析算法

引用計(jì)數(shù)法是什么

對象中設(shè)置一個引用計(jì)數(shù)器,每當(dāng)有一個地方引用它時仅讽,計(jì)數(shù)器值加1陶缺。引用失效時,計(jì)數(shù)器值減1洁灵。

計(jì)數(shù)器值為0的對象就是可被回收的對象饱岸。

引用計(jì)數(shù)法有什么優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn):實(shí)現(xiàn)簡單,判定效率高
  • 缺點(diǎn):無法解決對象直接相互循環(huán)引用的問題

什么是對象間的相互循環(huán)引用

例如:對象A和對象B都有字段ref, 現(xiàn)在讓A.ref=B, B.ref=A

然后手動執(zhí)行GC, 雖然這兩個對象不可能再被訪問徽千,但他們之間的相互引用讓引用計(jì)數(shù)器都不等于0苫费,無法被回收。

java虛擬機(jī)使用的是引用計(jì)數(shù)法嗎

不是双抽,因?yàn)閷ο笾苯酉嗷パh(huán)引用的問題百框,java虛擬機(jī)使用的是可達(dá)性分析算法

什么是可達(dá)性分析算法

通過一系列的GC Roots的對象作為起始點(diǎn),從這些起始點(diǎn)開始向下搜索牍汹,搜索走過的路徑被稱為引用鏈

當(dāng)一個對象到GC Roots沒有任何應(yīng)用鏈相連铐维,則證明對象是不可用的。

也可以說慎菲,從GC Roots到對象不可達(dá)時嫁蛇,則對象可回收。

一系列的GC Roots對象露该,GC Roots對象有哪些

  1. 虛擬機(jī)棧中引用的對象睬棚,即棧幀中本地變量表中對象
  2. 方法區(qū)中類靜態(tài)屬性引用的對象
  3. 方法區(qū)中常量引用的對象
  4. 本地方法棧中JNI,即Native方法中引用的對象。

當(dāng)GC Roots到對象不可達(dá)時,對象就一定可以被回收嗎

當(dāng)GC Roots到對象不可達(dá)時抑党,對象不一定會被回收包警,需要經(jīng)歷兩次標(biāo)記。

  1. 第一次GC Roots 到對象不可達(dá)時新荤,對象被標(biāo)記1次揽趾。
  2. 判斷對象是否覆蓋了finalize()方法
    • 對象覆蓋了finalize()方法,判斷虛擬機(jī)是否執(zhí)行了finalize方法
      • 虛擬機(jī)沒有執(zhí)行finalize方法苛骨,將對象放入F-Queue隊(duì)列中篱瞎,待回收
        • 稍后虛擬機(jī)自動建立低優(yōu)先級的Finalizer線程執(zhí)行F-Queue隊(duì)列中對象的finalize方法。
          • finalize方法中對象與引用鏈上鏈接建立關(guān)聯(lián)痒芝,即GC Roots到對象可達(dá)
          • finalize方法中對象沒有雨引用鏈上鏈接建立關(guān)聯(lián)
        • 稍后GC對F-Queue隊(duì)列中對象進(jìn)行第二次標(biāo)記
          • 與引用鏈建立鏈接的對象俐筋,移除待回收集合
          • 沒有與引用鏈建立鏈接的對象,對象可回收
      • 虛擬機(jī)已經(jīng)執(zhí)行了finalize方法严衬,對象可回收
    • 對象沒有覆蓋finalize()方法澄者,對象可回收

虛擬機(jī)自動建立的低優(yōu)先級的Finalizer線程執(zhí)行的時間很長怎么辦

Finalizer線程中對象finalize方法可能并不會等待方法執(zhí)行結(jié)束,因?yàn)閒inalize方法可能出現(xiàn)死循環(huán)等異常情況请琳,導(dǎo)致整個內(nèi)存回收機(jī)制崩潰粱挡。

所以只要執(zhí)行了finalize方法的對象,且沒有與引用鏈建立關(guān)聯(lián)俄精,對象就是可回收的询筏。雖然可能方法沒有結(jié)束。

對象的finalize方法有點(diǎn)像C++的析構(gòu)函數(shù)呀

是的竖慧,finalize方法就是Java對C++做出的妥協(xié)嫌套。
盡量不要使用這個方法,try-catch-finally可以做的更好圾旨。

方法區(qū)或永久代也可能被GC嗎

方法區(qū)或永久代也會被GC, 雖然效率會很低踱讨。

方法區(qū)或永久代會回收兩部分內(nèi)容:

  1. 廢棄常量
  2. 無用的類

這里的常量是指什么

這里是指運(yùn)行時常量池中常量:字面量和符號引用

常量如何判斷可回收

  1. 堆中沒有對象引用該字面量或符號引用
  2. 其他地方也沒有引用該字面量或符號引用

jdk1.8移除了永生代,會有什么變化嗎

常量被移到堆中砍的,即常量的回收與對象的回收一致了痹筛。
所以jdk1.8只負(fù)責(zé)類回收。

類如何判斷可回收

條件苛刻挨约,下面3個條件同時滿足才可以回收

  1. 該類所有實(shí)例被回收味混,即java堆中不存在該類的任何實(shí)例
  2. 加載該類的ClassLoader已經(jīng)被回收
  3. 該類對應(yīng)的java.lang.Class對象沒有在任何地方被引用,無法在任何地方通過反射訪問該類的方法诫惭。

而且是否對類進(jìn)行回收,虛擬機(jī)還提供參數(shù)進(jìn)行控制:-Xnoclassgc, 是否開啟類回收蔓挖。

總結(jié)

對象存活判定算法

  1. 引用計(jì)數(shù)法
  • 原理:對象中設(shè)置一個引用計(jì)數(shù)器夕土,當(dāng)有地方引用它時,計(jì)數(shù)器+1,引用失效時怨绣,計(jì)數(shù)器-1角溃,當(dāng)計(jì)數(shù)器==0時,對象已死篮撑。
  • 優(yōu)點(diǎn):實(shí)現(xiàn)簡單减细,判定效率高
  • 缺點(diǎn):無法解決對象間直接相互循環(huán)引用問題。
  1. 可達(dá)性分析算法
  • 原理:一系列的GC Roots對象作為起始點(diǎn)赢笨,向下搜索未蝌,走過的路徑被稱為引用鏈。當(dāng)一個對象到GC Roots沒有一個引用鏈相連茧妒,或者說GC Roots到對象不可達(dá)時萧吠,對象已死
  • 優(yōu)點(diǎn):解決對象間直接相互循環(huán)引用的問題
  • GC Roots對象:
    1. 虛擬機(jī)棧中引用的對象,即棧幀中本地變量表的引用對象
    2. 本地方法棧中JNI,即Native方法中對象
    3. 方法區(qū)中靜態(tài)變量引用的對象
    4. 方法區(qū)中常量引用的對象

對象兩次標(biāo)記判定算法

  • 原理:對象的fianlize方法可以第一次標(biāo)記已死的對象重新存活桐筏。
  • 步驟:
    1. 判斷對象是否覆蓋finalize方法或者判斷虛擬機(jī)是否已經(jīng)執(zhí)行了finalize方法
    2. 如果沒有覆蓋finalize方法或已經(jīng)執(zhí)行了finalize方法纸型,則對象必死
    3. 如果對象覆蓋了finalize方法且虛擬機(jī)沒有執(zhí)行finalize方法,將對象放到F-Queue隊(duì)列中
    4. 稍后虛擬機(jī)自動建立低優(yōu)先級的線程梅忌,執(zhí)行F-Queue隊(duì)列中對象的finalize方法狰腌,因虛擬機(jī)資源和效率,不一定會等待所有對象的finalize方法執(zhí)行完成牧氮。
    5. 稍候GC對F-Queue隊(duì)列中對象進(jìn)行第二次標(biāo)記琼腔,如果對象在finalize方法中與引用鏈重新建立鏈接,即第二次標(biāo)記存活的對象蹋笼,移出待回收集合展姐。如果第二次標(biāo)記還是死亡,則對象必死剖毯。

方法區(qū)回收判定算法

  1. 常量判定
    • 常量內(nèi)容:字面量和符號引用
    • 判定算法:
      • 堆中沒有對象引用該字面量或符號引用
      • 其他地方?jīng)]有引用該字面量或符號引用
  2. 類判定
    • 虛擬機(jī)啟用類回收卸載
      • 使用參數(shù):-Xnoclassgc圾笨,啟用類回收卸載
    • 類信息同時滿足3個條件判定可卸載
      • 堆中沒有該類的任何實(shí)例對象
      • 該類的ClassLoader被卸載
      • 該類對應(yīng)的java.lang.Class對象沒有在任何地方被引用,無法通過反射機(jī)制引用到該類

垃圾回收算法

垃圾回收算法有哪幾種

  1. 標(biāo)記清除
  2. 復(fù)制算法
  3. 標(biāo)記整理
  4. 分代收集

什么是標(biāo)記清除算法

  1. 標(biāo)記:標(biāo)記出所有待回收的對象逊谋。
  2. 清除:標(biāo)記完成擂达,統(tǒng)一回收被標(biāo)記對象的內(nèi)存。

標(biāo)記清除算法有什么優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn):實(shí)現(xiàn)簡單
  • 缺點(diǎn):
    1. 標(biāo)記和清除的效率都不高胶滋。
    2. 一次GC后會產(chǎn)生大量的不連續(xù)的內(nèi)存碎片板鬓,當(dāng)分配大對象時,可能會無法分配內(nèi)存而重新發(fā)起一次GC

什么是復(fù)制算法

  1. 將堆內(nèi)存分為大小相等兩塊區(qū)域究恤,每次只用其中一塊
  2. 當(dāng)使用的那一塊內(nèi)存使用完畢俭令,觸發(fā)一次GC, 將存活的對象復(fù)制到另外一塊,已使用過的內(nèi)存空間一次清理部宿。
  3. 復(fù)制時只移動堆頂指針抄腔,按順序分配內(nèi)存瓢湃,不會有大量內(nèi)存碎片出現(xiàn)

復(fù)制算法有什么優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn):解決了標(biāo)記清除算法的效率問題和內(nèi)存碎片問題
  • 缺點(diǎn):一次只能用一半的內(nèi)存空間,空間消耗太大

復(fù)制算法如何優(yōu)化內(nèi)存空間消耗太大的問題

IBM的研究表明: 98%的對象朝生夕死赫蛇,熬過一次GC的對象極少绵患,所以并不需要按1:1等比例來劃分內(nèi)存空間。

內(nèi)存劃分:

  1. Eden空間:占內(nèi)存80%悟耘,數(shù)量1
  2. Survivor空間:占內(nèi)存10%落蝙,數(shù)量2
    • From空間
    • To空間

每次使用Eden空間和Survivor空間中一個,即使用90%的空間暂幼,剩余10%的空間筏勒。
畢竟98%只是一般理論數(shù)據(jù),10%的空間足夠存放理論上2%的存活對象粟誓。

發(fā)生GC時奏寨,將存活對象(理論上2%)復(fù)制到Survivor的另一塊空閑空間,Eden空間和已使用的一塊Survivor空間回收內(nèi)存鹰服。

98%畢竟是理論值病瞳,如果超過10%的對象熬過GC, 特別是大對象,那該怎么辦

98%的對象朝生夕死悲酷,根據(jù)對象生存周期的不同可以將java堆內(nèi)存分為兩種:新生代和老年代套菜。

開始內(nèi)存都在新生代中分配,每熬過一次GC, 對象年齡+1设易,當(dāng)對象年齡到15歲時逗柴,移到老年代。

很顯然顿肺,新生代的對象適合用復(fù)制算法戏溺。但如果10%的空間不夠,會用老年代的空間進(jìn)行擔(dān)保屠尊,進(jìn)入老年代的空間旷祸。

能熬過15次GC的老年代中對象,存活率肯定比較高讼昆,用復(fù)制算法的10%空間根本不夠吧

是的托享,老年代中對象存活率很高,不適合使用復(fù)制算法浸赫,所以使用標(biāo)記整理算法闰围。

什么是標(biāo)記整理算法

  1. 標(biāo)記:對所有可回收的對象進(jìn)行標(biāo)記
  2. 整理:標(biāo)記完成后,所有存活的對象向一端移動既峡,然后直接清理存活對象邊界之外的內(nèi)存空間羡榴。

標(biāo)記整理算法有什么優(yōu)缺點(diǎn)

  • 優(yōu)點(diǎn):解決了標(biāo)記整理的大量內(nèi)存碎片的問題,適合老年代运敢。老年代對象存活率高炕矮,沒有額外空間對它進(jìn)行分配擔(dān)保么夫。
  • 缺點(diǎn):不適合新生代者冤。新生代對象存活率低肤视,沒有復(fù)制算法效率高。

那新生代就用復(fù)制算法涉枫,老年代就用標(biāo)記整理算法就好了

是的邢滑,這就是分代算法

  1. 新生代對象存活率低,使用復(fù)制算法愿汰,只需復(fù)制少量對象就完成收集困后。
  2. 老年代存活率高,且沒有額外空間擔(dān)保衬廷,必須用標(biāo)記整理算法回收空間摇予。

總結(jié)

堆內(nèi)存分代

  • 原因:98%的對象朝生夕死
  • 分代:
  1. 新生代
    • 存放對象:對象起始都在新生代分配,每熬過一次GC,對象年齡+1吗跋,對象到15歲侧戴,移到老年代。
    • 復(fù)制算法空間劃分:使用復(fù)制算法對新生代空間劃分
      • Eden空間:占用新生代80%跌宛,1個酗宋,使用的空間。
      • Survivor空間:占用新生代20%疆拘,2個蜕猫,使用其中之一。
        • From空間哎迄,占用新生代10%
        • To空間回右,占用新生代10%
  2. 老年代

垃圾收集算法

  1. 標(biāo)記清除
    • 原理:標(biāo)記所有待回收的對象,標(biāo)記完成漱挚,清理所有待回收對象內(nèi)存空間翔烁。
    • 優(yōu)點(diǎn):實(shí)現(xiàn)簡單
    • 缺點(diǎn):標(biāo)記和清理效率不高,而且產(chǎn)生大量內(nèi)存碎片棱烂。
  2. 復(fù)制算法
    • 原理:
      • 將新生代分為兩部分空間租漂,一塊Eden空間(占用80%空間)和兩塊Survivor空間(分別占用10%空間),每次只使用Eden空間和一塊Survivor空間颊糜,即使用90%空間哩治。
      • 發(fā)生GC時,將存活的對象復(fù)制到另一塊空閑的Survivor空間衬鱼,Eden空間和已使用的Survivor空間一次清理业筏。
    • 優(yōu)點(diǎn):適合收集新生代朝生夕死的對象,只需復(fù)制少量的存活對象完成收集鸟赫,且不會產(chǎn)生大量內(nèi)存碎片蒜胖。
    • 缺點(diǎn):存活對象超過10%時消别,需要擔(dān)保進(jìn)入老年代。
  3. 標(biāo)記整理
    • 原理:標(biāo)記所有待回收對象台谢,標(biāo)記完成寻狂,將存活對象移到一端,端邊界之外的內(nèi)存空間一次清理朋沮。
    • 優(yōu)點(diǎn):適合對象存活率高蛇券,且無法擔(dān)保的老年代。也不會產(chǎn)生大量內(nèi)存碎片樊拓。
    • 缺點(diǎn):標(biāo)記和整理效率不高纠亚。
  4. 分代算法
    • 原理:在新生代使用復(fù)制算法,只需復(fù)制少量對象即可完成收集筋夏。在老年代使用標(biāo)記整理算法蒂胞,老年代對象存活率高,且無法擔(dān)保条篷。

想共同學(xué)習(xí)jvm的可以加我微信:1832162841骗随,或者進(jìn)QQ群:982523529

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拥娄,隨后出現(xiàn)的幾起案子蚊锹,更是在濱河造成了極大的恐慌,老刑警劉巖稚瘾,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件牡昆,死亡現(xiàn)場離奇詭異,居然都是意外死亡摊欠,警方通過查閱死者的電腦和手機(jī)丢烘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來些椒,“玉大人播瞳,你說我怎么就攤上這事∶飧猓” “怎么了赢乓?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長石窑。 經(jīng)常有香客問我牌芋,道長,這世上最難降的妖魔是什么松逊? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任躺屁,我火速辦了婚禮,結(jié)果婚禮上经宏,老公的妹妹穿的比我還像新娘犀暑。我一直安慰自己驯击,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布耐亏。 她就那樣靜靜地躺著徊都,像睡著了一般。 火紅的嫁衣襯著肌膚如雪苹熏。 梳的紋絲不亂的頭發(fā)上碟贾,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天,我揣著相機(jī)與錄音轨域,去河邊找鬼。 笑死杀餐,一個胖子當(dāng)著我的面吹牛干发,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播史翘,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼枉长,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了琼讽?” 一聲冷哼從身側(cè)響起必峰,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎钻蹬,沒想到半個月后吼蚁,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡问欠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年肝匆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顺献。...
    茶點(diǎn)故事閱讀 40,435評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡旗国,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出注整,到底是詐尸還是另有隱情能曾,我是刑警寧澤,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布肿轨,位于F島的核電站寿冕,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏萝招。R本人自食惡果不足惜蚂斤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望槐沼。 院中可真熱鬧曙蒸,春花似錦捌治、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至臂港,卻和暖如春森枪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背审孽。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工县袱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人佑力。 一個月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓式散,卻偏偏與公主長得像,于是被迫代替她去往敵國和親打颤。 傳聞我的和親對象是個殘疾皇子暴拄,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,442評論 2 359

推薦閱讀更多精彩內(nèi)容