深入解析Java垃圾回收機(jī)制

  • 引入垃圾回收
  • 哪些內(nèi)存需要回收?
    • 引用計(jì)數(shù)法
    • 可達(dá)性分析
  • 如何回收
    • Marking 標(biāo)記
    • Normal Deletion 清除
    • Deletion with Compacting 壓縮
  • 為什么需要分代收集绅你?
  • JVM的分代
    • 新生代
    • 老年代
    • 永久代
  • 分代垃圾收集過(guò)程詳述

引入垃圾回收

程序計(jì)數(shù)器近迁、 虛擬機(jī)棧嚎卫、 本地方法棧3個(gè)區(qū)域隨線程而生狰域,隨線程而滅永部;棧中的棧幀隨著方法的進(jìn)入和退出而有條不紊地執(zhí)行著出棧和入棧操作字管。 每一個(gè)棧幀中分配多少內(nèi)存基本上是在類結(jié)構(gòu)確定下來(lái)時(shí)就已知的(盡管在運(yùn)行期會(huì)由JIT編譯器
進(jìn)行一些優(yōu)化啰挪,但在本章基于概念模型的討論中信不,大體上可以認(rèn)為是編譯期可知的),因此這幾個(gè)區(qū)域的內(nèi)存分配和回收都具備確定性亡呵,在這幾個(gè)區(qū)域內(nèi)就不需要過(guò)多考慮回收的問(wèn)題抽活,因?yàn)榉椒ńY(jié)束或者線程結(jié)束時(shí),內(nèi)存自然就跟隨著回收了锰什。 而Java堆和方法區(qū)則不一樣下硕,一個(gè)接口中的多個(gè)實(shí)現(xiàn)類需要的內(nèi)存可能不一樣,一個(gè)方法中的多個(gè)分支需要的內(nèi)存也可能不一樣汁胆,我們只有在程序處于運(yùn)行期間時(shí)才能知道會(huì)創(chuàng)建哪些對(duì)象梭姓,這部分內(nèi)存的分配和回收都是動(dòng)態(tài)的,垃圾收集器所關(guān)注的是這部分內(nèi)存-----《深入理解Java虛擬機(jī)》

自動(dòng)垃圾回收機(jī)制就是尋找Java堆中的對(duì)象嫩码,并對(duì)對(duì)象進(jìn)行分類判別誉尖,尋找出正在使用的對(duì)象和已經(jīng)不會(huì)使用的對(duì)象,然后把那些不會(huì)使用的對(duì)象從堆上清除铸题。
自動(dòng)垃圾回收機(jī)制就是要解決三個(gè)問(wèn)題:

  • 哪些內(nèi)存需要回收铡恕?
  • 什么時(shí)候回收?
  • 如何回收丢间?

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

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

對(duì)于第一個(gè)問(wèn)題,也就是判斷是否還需要使用烘挫,最簡(jiǎn)單的方法就是通過(guò)目前是否有引用指向這個(gè)對(duì)象诀艰,如果沒(méi)有就說(shuō)明這個(gè)對(duì)象不會(huì)再被使用了,如果有就說(shuō)明這個(gè)對(duì)象可能還會(huì)繼續(xù)被使用饮六,這種通過(guò)引用是否存在的方法就叫做引用計(jì)數(shù)法涡驮,但這個(gè)方法存在一個(gè)問(wèn)題就是無(wú)法解決對(duì)象循環(huán)引用的問(wèn)題,因此又出現(xiàn)了可達(dá)性分析的方法來(lái)判斷對(duì)象是否可以被會(huì)回收喜滨。

可達(dá)性分析

這個(gè)算法的基本思路就是通過(guò)一系列的稱為“GC Roots”的對(duì)象作為起始點(diǎn)捉捅,從這些節(jié)點(diǎn)開始向下搜索,搜索所走過(guò)的路徑稱為引用鏈(Reference Chain)虽风,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈相連(用圖論的話來(lái)說(shuō)棒口,就是從GC Roots到這個(gè)對(duì)象不可達(dá))時(shí),則證明此對(duì)象是不可用的辜膝。
在Java語(yǔ)言中无牵,可作為GC Roots的對(duì)象包括下面幾種:

  • 虛擬機(jī)棧(棧幀中的本地變量表)中引用的對(duì)象。
  • 方法區(qū)中類靜態(tài)屬性引用的對(duì)象厂抖。
  • 方法區(qū)中常量引用的對(duì)象茎毁。
  • 本地方法棧中JNI(即一般說(shuō)的Native方法)引用的對(duì)象。

如何回收

垃圾收集器通常會(huì)幫我們?cè)诤笈_(tái)自動(dòng)進(jìn)行垃圾回收。關(guān)于具體的回收過(guò)程只要有以下這些步驟

  • Step 1: Marking 標(biāo)記

第一步就是標(biāo)記七蜘,也就是垃圾收集器會(huì)找出那些需要回收的對(duì)象所在的內(nèi)存和不需要回收的對(duì)象所在的內(nèi)存谭溉,并把它們標(biāo)記出來(lái),簡(jiǎn)單的說(shuō)橡卤,也就是先找出垃圾在哪

image.png

所有堆中的對(duì)象都會(huì)被掃描一遍扮念,以此來(lái)確定回收的對(duì)象,所以這通常會(huì)是一個(gè)相對(duì)比較耗時(shí)的過(guò)程

  • Step 2: Normal Deletion
    垃圾收集器會(huì)清除掉上一步標(biāo)記出來(lái)的那些需要回收的對(duì)象區(qū)域
image.png

存在的問(wèn)題就是碎片問(wèn)題:
標(biāo)記清除之后會(huì)產(chǎn)生大量不連續(xù)的內(nèi)存碎片碧库,空間碎片太多可能會(huì)導(dǎo)致以后在程
序運(yùn)行過(guò)程中需要分配較大對(duì)象時(shí)柜与,無(wú)法找到足夠的連續(xù)內(nèi)存而不得不提前觸發(fā)另一次垃圾收集動(dòng)作。

  • Step 2a: Deletion with Compacting 壓縮
    由于簡(jiǎn)單的清除可能會(huì)存在碎片的問(wèn)題嵌灰,所以又出現(xiàn)了壓縮清除的方法弄匕,也就是先清除需要回收的對(duì)象,然后再對(duì)內(nèi)存進(jìn)行壓縮操作沽瞭,將內(nèi)存分成可用和不可用兩大部分
image.png

為什么需要分代收集迁匠?

就像前文所述,標(biāo)記對(duì)象和壓縮內(nèi)存的過(guò)程在JVM中是不高效的秕脓,分配的對(duì)象越多,垃圾收集的時(shí)間就越長(zhǎng)儒搭。但是吠架,經(jīng)過(guò)一些經(jīng)驗(yàn)型性的統(tǒng)計(jì)分析表明,一個(gè)程序中大部分對(duì)象都是短命的搂鲫!

下圖就是一個(gè)類似的統(tǒng)計(jì)數(shù)據(jù)傍药,縱坐標(biāo)表示分配對(duì)象所占用的內(nèi)存大小,橫坐標(biāo)表示自分配對(duì)象過(guò)去的時(shí)間

image.png

從圖中我們看到魂仍,大部分對(duì)象沒(méi)活多久就死了拐辽,存活較久的只是少類對(duì)象

JVM的分代

為了增大垃圾收集的效率,所以JVM將堆進(jìn)行分代擦酌,分為不同的部分俱诸,一般有三部分,新生代赊舶,老年代和永久代

image.png

新生代

所有新new出來(lái)的對(duì)象都會(huì)最先出現(xiàn)在新生代中睁搭,當(dāng)新生代這部分內(nèi)存滿了之后,就會(huì)發(fā)起一次垃圾收集事件笼平,這種發(fā)生在新生代的垃圾收集稱為Minor collections园骆。這種收集通常比較快,因?yàn)樾律拇蟛糠謱?duì)象都是需要回收的寓调,那些暫時(shí)無(wú)法回收的就會(huì)被移動(dòng)到老年代锌唾。

Stop the World事件-所有minor garbage collections都是Stop the World事件,也就是意味著所有的應(yīng)用線程都需要停止夺英,直到垃圾回收的操作全部完成晌涕。類似于
“你媽媽在給你打掃房間的時(shí)候滋捶,肯定也會(huì)讓你老老實(shí)實(shí)地在椅子上或者房間外待著,如果她一邊打掃渐排,你一邊亂扔紙屑异雁,這房間還能打掃完锁蠕?”

老年代

老年代用來(lái)存儲(chǔ)那些存活時(shí)間較長(zhǎng)的對(duì)象。一般來(lái)說(shuō),我們會(huì)給新生代的對(duì)象限定一個(gè)存活的時(shí)間蹋半,當(dāng)達(dá)到這個(gè)時(shí)間還沒(méi)有被收集的時(shí)候就會(huì)被移動(dòng)到老年代中。老年代區(qū)域的垃圾收集叫做major garbage collection

image.png

Major garbage collection也是一個(gè)Stop the World事件弃甥。通常Major garbage collection都相對(duì)比較慢惶室,因?yàn)槔夏甏氖占藢?duì)所有對(duì)象的收集,也就是同時(shí)需要收集新生代和老年代的對(duì)象帘靡。

永久代

The Permanent generation contains metadata required by the JVM to describe the classes and methods used in the application. The permanent generation is populated by the JVM at runtime based on classes in use by the application. In addition, Java SE library classes and methods may be stored here.

Classes may get collected (unloaded) if the JVM finds they are no longer needed and space may be needed for other classes. The permanent generation is included in a full garbage collection.

image.png

分代垃圾收集過(guò)程詳述

我們已經(jīng)知道垃圾回收所需要的方法和堆內(nèi)存的分代知给,那么接下來(lái)我們就來(lái)具體看一下垃圾回收的具體過(guò)程

  • 第一步 所有new出來(lái)的對(duì)象都會(huì)最先分配到新生代區(qū)域中,兩個(gè)survivor區(qū)域初始化是為空的
image.png
  • 第二步描姚,當(dāng)eden區(qū)域滿了之后涩赢,就引發(fā)一次 minor garbage collection
image.png
  • 第三步,當(dāng)在minor garbage collection轩勘,存活下來(lái)的對(duì)象就會(huì)被移動(dòng)到S0survivor區(qū)域
image.png
  • 第四步筒扒,然后當(dāng)eden區(qū)域又填滿的時(shí)候,又會(huì)發(fā)生下一次的垃圾回收绊寻,存活的對(duì)象會(huì)被移動(dòng)到survivor區(qū)域而未存活對(duì)象會(huì)被直接刪除花墩。但是,不同的是澄步,在這次的垃圾回收中冰蘑,存活對(duì)象和之前的survivor中的對(duì)象都會(huì)被移動(dòng)到s1中。一旦所有對(duì)象都被移動(dòng)到s1中村缸,那么s2中的對(duì)象就會(huì)被清除祠肥,仔細(xì)觀察圖中的對(duì)象,數(shù)字表示經(jīng)歷的垃圾收集的次數(shù)梯皿。目前我們已經(jīng)有不同的年齡對(duì)象了搪柑。
image.png
  • 第五步,下一次垃圾回收的時(shí)候索烹,又會(huì)重復(fù)上次的步驟工碾,清除需要回收的對(duì)象,并且又切換一次survivor區(qū)域百姓,所有存活的對(duì)象都被移動(dòng)至s0渊额。eden和s1區(qū)域被清除。
image.png
  • 第六步,重復(fù)以上步驟旬迹,并記錄對(duì)象的年齡火惊,當(dāng)有對(duì)象的年齡到達(dá)一定的閾值的時(shí)候,就將新生代中的對(duì)象移動(dòng)到老年代中奔垦。在本例中屹耐,這個(gè)閾值為8.
image.png
  • 第七步,接下來(lái)垃圾收集器就會(huì)重復(fù)以上步驟椿猎,不斷的進(jìn)行對(duì)象的清除和年代的移動(dòng)
image.png
  • 最后惶岭,我們觀察上述過(guò)程可以發(fā)現(xiàn),大部分的垃圾收集過(guò)程都是在新生代進(jìn)行的犯眠,直到老年代中的內(nèi)存不夠用了才會(huì)發(fā)起一次 major GC按灶,會(huì)進(jìn)行標(biāo)記和整理壓縮。
image.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末筐咧,一起剝皮案震驚了整個(gè)濱河市鸯旁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌量蕊,老刑警劉巖铺罢,帶你破解...
    沈念sama閱讀 212,185評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異残炮,居然都是意外死亡韭赘,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,445評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門吉殃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)辞居,“玉大人楷怒,你說(shuō)我怎么就攤上這事蛋勺。” “怎么了鸠删?”我有些...
    開封第一講書人閱讀 157,684評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵抱完,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我刃泡,道長(zhǎng)巧娱,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,564評(píng)論 1 284
  • 正文 為了忘掉前任烘贴,我火速辦了婚禮禁添,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘桨踪。我一直安慰自己老翘,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,681評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著铺峭,像睡著了一般墓怀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上卫键,一...
    開封第一講書人閱讀 49,874評(píng)論 1 290
  • 那天傀履,我揣著相機(jī)與錄音,去河邊找鬼莉炉。 笑死钓账,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的呢袱。 我是一名探鬼主播官扣,決...
    沈念sama閱讀 39,025評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼羞福!你這毒婦竟也來(lái)了惕蹄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,761評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤治专,失蹤者是張志新(化名)和其女友劉穎卖陵,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體张峰,經(jīng)...
    沈念sama閱讀 44,217評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡泪蔫,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,545評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了喘批。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撩荣。...
    茶點(diǎn)故事閱讀 38,694評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖饶深,靈堂內(nèi)的尸體忽然破棺而出餐曹,到底是詐尸還是另有隱情,我是刑警寧澤敌厘,帶...
    沈念sama閱讀 34,351評(píng)論 4 332
  • 正文 年R本政府宣布台猴,位于F島的核電站,受9級(jí)特大地震影響俱两,放射性物質(zhì)發(fā)生泄漏饱狂。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,988評(píng)論 3 315
  • 文/蒙蒙 一宪彩、第九天 我趴在偏房一處隱蔽的房頂上張望休讳。 院中可真熱鬧,春花似錦尿孔、人聲如沸俊柔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,778評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)婆咸。三九已至竹捉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間尚骄,已是汗流浹背块差。 一陣腳步聲響...
    開封第一講書人閱讀 32,007評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留倔丈,地道東北人憨闰。 一個(gè)月前我還...
    沈念sama閱讀 46,427評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像需五,于是被迫代替她去往敵國(guó)和親鹉动。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,580評(píng)論 2 349

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