Java — 垃圾收集靈魂拷問三連

前言

說到GC,一直沒有系統(tǒng)的看過允蚣。但是于颖,很顯然,是一個非常經(jīng)典的知識點嚷兔。毫不夸張的說森渐,面試的時候問道GC而你一無所知的話,基本上是涼了冒晰。

今天拜讀了JVM經(jīng)典書《深入理解Java虛擬機》同衣,對于GC講的很詳細。書中在第三章講的是垃圾收集器與內(nèi)存分配策略壶运,我準備分三篇文章來記錄這章的讀書筆記耐齐,本篇介紹一下垃圾回收流程,第二篇介紹垃圾收集器,第三篇介紹新老生代的劃分以及內(nèi)存分配策略蚪缀。本篇更偏向于理論和算法思想秫逝,所以看起來還是很有趣的。值得注意的是询枚,我們只有在程序處于運行期間才知道創(chuàng)建了哪些對象违帆,這部分內(nèi)存的分配和回收是動態(tài)的,垃圾收集關(guān)注的也是這部分內(nèi)存金蜀。學習GC通俗來說也就三個問題:

哪些內(nèi)存需要回收刷后?

什么時候回收?

如何回收

下面渊抄,我們也根據(jù)這三個問題來逐步了解GC尝胆。

哪些內(nèi)存需要回收?

對象占用內(nèi)存护桦,所以不再使用的對象所占用的內(nèi)存需要回收含衔。那么,怎么判斷對象不再使用呢二庵?判斷對象是否 “死亡” 有以下方法:

引用計數(shù)算法

給對象中添加一個引用計數(shù)器贪染,每當有一個地方引用它時,計數(shù)器值就加1催享;當引用失效時杭隙,計數(shù)器值就減1;任何時刻計數(shù)器都為0的對象就是不可能在被使用的因妙。引用計數(shù)算法實現(xiàn)簡單痰憎,判斷效率也很高,在大部分情況下都是一個不錯的算法攀涵。但是铣耘,在Java中并沒有選擇引用計數(shù)算法來管理內(nèi)存,其中最主要的原因是它很難解決對象之間的相互循環(huán)引用的問題汁果。

根搜索算法

Java中涡拘,是用根搜索算法來判斷對象是否存活的玲躯。這個算法的思路就是通過一系列的名為 “GC Roots” 的對象作為起始點据德,從這個節(jié)點開始向下搜索,搜索所有走過的路徑稱為引用鏈(Reference Chain)跷车,當一個對象到了GC Roots沒有任何引用鏈相連的時候(不可達)棘利,則說明此對象是不可用的,被判定為可回收對象朽缴。

一圖勝千言:(圖是槍來的……)

根據(jù)引用判斷

無論是通過引用計數(shù)算法判斷對象的引用數(shù)量善玫,還是通過根搜索算法判斷對象的引用鏈是否可達,判斷對象是否存活都與引用有關(guān)密强。

強引用(Strong Reference)

在代碼中普遍存在茅郎,類似 Object obj = new Object() 蜗元。只要強引用還存在,垃圾收集器永遠不會回收掉被引用的對象系冗。

軟引用(Soft Reference)

用來描述一些還有用奕扣,但并非必須的對象。對于軟引用關(guān)聯(lián)的對象掌敬,在系統(tǒng)將要發(fā)生OOM異常之前惯豆,將會把這些對象列進回收范圍之中并進行第二次回收。如果這次回收還是沒有足夠的內(nèi)存奔害,才會拋出內(nèi)存溢出異常楷兽。在JDK1.2之后,提供了SoftReference類實現(xiàn)軟引用华临。

弱引用(Weak Reference)

也是用來描述非必須對象芯杀,但是它的強度比軟引用更弱一些,被弱引用關(guān)聯(lián)的對象只能生存到下一次垃圾收集發(fā)生之前雅潭。當垃圾收集器工作時瘪匿,無論當前內(nèi)存是否足夠,都會回收掉只有被弱引用關(guān)聯(lián)的對象寻馏。在JDK1.2之后棋弥,提供了WeakReference類實現(xiàn)弱引用。

虛引用(Phantom Reference)

它是最弱的一種引用關(guān)系诚欠。一個對象是否有虛引用的存在顽染,完全不會對其生存時間構(gòu)成影響,也無法通過虛引用來取得一個對象實例轰绵。為一個對象設(shè)置虛引用關(guān)聯(lián)的唯一目的就是希望能在這個對象被收集器回收時收到一個系統(tǒng)通知粉寞。在JDK1.2之后,提供了PhantomReference類來實現(xiàn)虛引用左腔。

什么時候回收唧垦?

當一個對象不可達時,并不是馬上就會被回收的液样。這里就要說一下finalize()方法振亮,這個方法被調(diào)用有三種情況:

所有對象被CG時自動調(diào)用,比如運行System.gc()的時候

程序退出時為每個對象調(diào)用一次finalize方法

顯式的調(diào)用finalize方法

再盜一張圖:

JVM 能夠保證一個對象在回收以前一定會調(diào)用一次它的finalize()方法鞭莽。

需要注意的是坊秸,你永遠不知道它什么時候被調(diào)用甚至會不會調(diào)用,因為有些對象永遠不會被回收的澎怒,或者被回收以前程序就已經(jīng)結(jié)束了褒搔。但是如果它有必要執(zhí)行finalize()的,那么在GC前一定調(diào)用一次且僅且一次,如果在第一次GC時沒有被回收星瘾,那么以后在GC時就不會在調(diào)用finalize()走孽。

如何回收?

那就要說說回收算法啦琳状。

標記清除算法(Mark-Sweep)

算法分為標記和清除兩個階段融求,首先標記出所有需要回收的對象,在標記完成后統(tǒng)一回收掉被標記的對象算撮。

缺點:

效率低下生宛,標記和清除的效率都不高

空間問題,標記清除后會產(chǎn)生大量不連續(xù)的內(nèi)存碎片肮柜,空間碎片太多可能會導致需要分配大對象無法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集陷舅。

復制算法(Copying)

它將可用內(nèi)存按容量劃分為大小相等的兩塊,每次只使用其中一塊审洞。當這一塊的內(nèi)存用完了莱睁,就將還存活的對象復制到另外一塊上面,然后再把已經(jīng)使用過的內(nèi)存空間一次清理掉芒澜。這樣使得每次都是對其中的一塊進行內(nèi)存回收仰剿,內(nèi)存分配也不用考慮內(nèi)存碎片等復雜問題,只要移動堆頂指針痴晦,按順序分配內(nèi)存即可南吮,實現(xiàn)簡單,運行高效誊酌。

當然部凑,缺點也很明顯,那就是要犧牲一半的內(nèi)存代價碧浊。

但是事實上涂邀,并不需要按1:1劃分殉挽,而是將內(nèi)存分為一塊較大的Eden空間和兩塊較小的Survivor空間鹃锈,每次使用Eden和其中一塊Survivor。當回收時州叠,將Eden和Survivor空間還存活的對象一次性的復制到另外一塊Survivor空間上驹止,最后清理掉Eden和剛剛用過的Survivor空間浩聋。HotSpot虛擬機默認Eden和Survivor的大小比例是8:1。但是幢哨,當對象存活率較高時就要執(zhí)行較多的復制操作赡勘,效率將會變低嫂便。

標記-整理算法(Mark-Compact)

此算法結(jié)合了標記清除和復制兩個算法的優(yōu)點捞镰,分為兩個階段:

第一階段從根節(jié)點開始標記所有被引用的對象

第二階段遍歷整個堆,把清除未標記對象并且把存活的對象壓縮到堆的其中一塊,按順序排放岸售。此算法避免了標記清除的碎片問題践樱,同時也避免了復制算法的空間問題。

分代收集算法(Generational Collection)

當前商業(yè)虛擬機的垃圾回收都采用分代收集算法凸丸,這種算法并沒有什么新的思想拷邢,只是根據(jù)對象的存活周期將內(nèi)存劃分為幾塊。一般是把Java堆分為新生代和老年代屎慢,這樣就可以根據(jù)各個年代的特點采用最適當?shù)氖占惴út稼。在新生代中,每次垃圾回收都有大批對象死去腻惠,只有少量存活环肘,那就選用復制算法,只要付出少量存活對象的復制成本就可以完成收集集灌。而老年代中因為對象存活率高悔雹,沒有額外的空間對它進行分配擔保,那就使用標記清理或者標記整理算法來進行回收欣喧。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腌零,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子唆阿,更是在濱河造成了極大的恐慌益涧,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件驯鳖,死亡現(xiàn)場離奇詭異饰躲,居然都是意外死亡,警方通過查閱死者的電腦和手機臼隔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門嘹裂,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人摔握,你說我怎么就攤上這事寄狼。” “怎么了氨淌?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵泊愧,是天一觀的道長。 經(jīng)常有香客問我盛正,道長删咱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任豪筝,我火速辦了婚禮痰滋,結(jié)果婚禮上摘能,老公的妹妹穿的比我還像新娘。我一直安慰自己敲街,他們只是感情好团搞,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著多艇,像睡著了一般逻恐。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上峻黍,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天复隆,我揣著相機與錄音,去河邊找鬼姆涩。 笑死昏名,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的阵面。 我是一名探鬼主播轻局,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼样刷!你這毒婦竟也來了仑扑?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤置鼻,失蹤者是張志新(化名)和其女友劉穎镇饮,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體箕母,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡储藐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了嘶是。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钙勃。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖聂喇,靈堂內(nèi)的尸體忽然破棺而出辖源,到底是詐尸還是另有隱情,我是刑警寧澤希太,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布克饶,位于F島的核電站,受9級特大地震影響誊辉,放射性物質(zhì)發(fā)生泄漏矾湃。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一堕澄、第九天 我趴在偏房一處隱蔽的房頂上張望邀跃。 院中可真熱鬧霉咨,春花似錦、人聲如沸坞嘀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽丽涩。三九已至,卻和暖如春裁蚁,著一層夾襖步出監(jiān)牢的瞬間矢渊,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工枉证, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留矮男,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓室谚,卻偏偏與公主長得像毡鉴,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子秒赤,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345