GC垃圾回收機制詳解

GC如其名,就是垃圾收集,當然這里僅就內(nèi)存而言底洗。Garbage Collector(垃圾收集器)以應用程序的root為基礎(chǔ)款筑,遍歷應用程序在Heap上動態(tài)分配的所有對象智蝠,通過識別它們是否被引用來確定哪些對象是已經(jīng)死亡的腾么、哪些仍需要被使用。已經(jīng)不再被應用程序的root或者別的對象所引用的對象就是已經(jīng)死亡的對象杈湾,即所謂的垃圾解虱,需要被回收回收的是該對象占用的內(nèi)存空間。這就是GC工作的原理漆撞。為了實現(xiàn)這個原理殴泰,GC有多種算法。比較常見的算法有Reference Counting浮驳,Mark Sweep悍汛,Copy Collection等等。目前主流的虛擬系統(tǒng).NET CLR至会,Java VM和Rotor都是采用的Mark Sweep算法离咐。


JVM堆相關(guān)知識??? 為什么先說JVM堆???

??JVM的堆是Java對象的活動空間,程序中的類的對象從中分配空間奋献,其存儲著正在運行著的應用程序用到的所有對象健霹。這些對象的建立方式就是那些new一類的操作,當對象無用后瓶蚂,是GC來負責這個無用的對象糖埋。

JVM堆???

?(1) 新域:存儲所有新成生的對象????新域會被分為3個部分:1.第一個部分叫Eden。2.另兩個部分稱為輔助生存空間(幼兒園)窃这,我這里一個稱為A空間(From sqace)瞳别,一個稱為B空間(To Space)。

(2) 舊域:新域中的對象杭攻,經(jīng)過了一定次數(shù)的GC循環(huán)后祟敛,被移入舊域???

?(3)永久域:存儲類和方法對象,從配置的角度看兆解,這個域是獨立的馆铁,不包括在JVM堆內(nèi)。默認為4M锅睛。?



垃圾回收的原因

從計算機組成的角度來講埠巨,所有的程序都是要駐留在內(nèi)存中運行的。而內(nèi)存是一個限制因素(大小)现拒。除此之外辣垒,托管堆也有大小限制。因為地址空間和存儲的限制因素印蔬,托管堆要通過垃圾回收機制勋桶,來維持它的正常運作,保證對象的分配,盡可能不造成“內(nèi)存溢出”例驹。



垃圾回收的基本原理算法思路都是一致的:把所有對象組成一個集合捐韩,或可以理解為樹狀結(jié)構(gòu),從樹根開始找眠饮,只要可以找到的都是活動對象奥帘,如果找不到,這個對象就被回收了


垃圾回收分為兩個階段:

標記 --> 壓縮標記的過程仪召,其實就是判斷對象是否可達的過程。當所有的根都檢查完畢后松蒜,堆中將包含可達(已標記)與不可達(未標記)對象扔茅。標記完成后,進入壓縮階段秸苗。在這個階段中召娜,垃圾回收器線性的遍歷堆,以尋找不可達對象的連續(xù)內(nèi)存塊惊楼。并把可達對象移動到這里以節(jié)約內(nèi)存空間玖瘸。




垃圾收集算法

Mark-Sweep標記清理算法

階段1: Mark-Sweep 標記清除階段,先假設heap中所有對象都可以回收檀咙,然后找出不能回收的對象雅倒,給這些對象打上標記,最后heap中沒有打標記的對象都是可以被回收的弧可;

階段2: Compact 壓縮階段蔑匣,對象回收之后heap內(nèi)存空間變得不連續(xù),在heap中移動這些對象棕诵,使他們重新從heap基地址開始連續(xù)排列(節(jié)省內(nèi)存資源)裁良。

Heap內(nèi)存經(jīng)過回收、壓縮之后校套,可以繼續(xù)采用前面的heap內(nèi)存分配方法价脾, 即僅用一個指針記錄heap分配的起始地址就可以。主要處理步驟:將線程掛起→確定roots→創(chuàng)建reachable objects graph→對象回收→heap壓縮→指針修復笛匙∏劝眩可以這樣理解roots:heap中對象的引用關(guān)系錯綜復雜(交叉引用、循環(huán)引用)膳算,形成復雜的 graph座硕,roots是CLR在heap之外可以找到的各種入口點。

  GC搜索roots的地方包括全局對象涕蜂、靜態(tài)變量华匾、局部對象、函數(shù)調(diào)用參數(shù)、當前CPU寄存器中的對象指針(還有finalization queue)等蜘拉。主要可以歸為2種類型:已經(jīng)初始化了的靜態(tài)變量萨西、線程仍在使用的對象(stack+CPU register)

指針修復是因為compact過程移動了heap對象,對象地址發(fā)生變化旭旭,需要修復所有引用指針谎脯,包括stack、CPU register中的指針以及heap中其他對象的引用指針持寄。


復制算法

新生代的內(nèi)存被劃分為一塊較大的Eden空間和兩塊較小的Survivor空間源梭,每次使用Eden和其中一塊Survivor。每次回收時稍味,將Eden和Survivor中還存活著的對象一次性復制到另外一塊Survivor空間上废麻,最后清理掉Eden和剛才用過的Survivor空間。HotSpot虛擬機默認Eden區(qū)和Survivor區(qū)的比例為8:1模庐,意思是每次新生代中可用內(nèi)存空間為整個新生代容量的90%烛愧。當然,我們沒有辦法保證每次回收都只有不多于10%的對象存活掂碱,當Survivor空間不夠用時怜姿,需要依賴老年代進行分配擔保(Handle Promotion)。


標記整理算法

與標記清理算法過程一樣疼燥,只是不直接清理可回收對象沧卢,而是將所有存活對象移動到一端,之后清理邊界之外的對象內(nèi)存




分代收集算法

?現(xiàn)代商用虛擬機基本都采用分代收集算法來進行垃圾回收悴了。這種算法沒什么特別的搏恤,無非是上面內(nèi)容的結(jié)合罷了,根據(jù)對象的生命周期的不同將內(nèi)存劃分為幾塊湃交,然后根據(jù)各塊的特點采用最適當?shù)氖占惴ㄊ炜铡4笈鷮ο笏廊ァ⑸倭繉ο蟠婊畹模ㄐ律└爿海褂脧椭扑惴ㄏ⒙蓿瑥椭瞥杀镜停粚ο蟠婊盥矢卟挪住]有額外空間進行分配擔保的(老年代)迈喉,采用標記-清理算法或者標記-整理算法。


?

?

?


如何找到需要回收的對象

1温圆、引用計數(shù)法:給對象中添加一個引用計數(shù)器挨摸,每當一個地方引用這個對象時,計數(shù)器值+1岁歉;當引用失效時得运,計數(shù)器值-1。任何時刻計數(shù)值為0的對象就是不可能再被使用的。

2熔掺、可達性分析法:對于可達性分析算法而言饱搏,未到達的對象并非是“非死不可”的,若要宣判一個對象死亡置逻,至少需要經(jīng)歷兩次標記階段推沸。

1. 如果對象在進行可達性分析后發(fā)現(xiàn)沒有與GCRoots相連的引用鏈,則該對象被第一次標記并進行一次篩選券坞,篩選條件為是否有必要執(zhí)行該對象的finalize方法鬓催,若對象沒有覆蓋finalize方法或者該finalize方法已經(jīng)被虛擬機執(zhí)行過了(?finalize()在什么時候被調(diào)用??有三種情況??????1.所有對象被Garbage Collection時自動調(diào)用,比如運行System.gc()的時候.??????2.程序退出時為每個對象調(diào)用一次finalize方法。??????3.顯式的調(diào)用finalize方法)恨锚,則均視作不必要執(zhí)行該對象的finalize方法深浮,即該對象將會被回收。反之眠冈,若對象覆蓋了finalize方法并且該finalize方法并沒有被執(zhí)行過,那么菌瘫,這個對象會被放置在一個叫F-Queue的隊列中蜗顽,之后會由虛擬機自動建立的、優(yōu)先級低的Finalizer線程去執(zhí)行雨让,而虛擬機不必要等待該線程執(zhí)行結(jié)束雇盖,即虛擬機只負責建立線程,其他的事情交給此線程去處理栖忠。

2.對F-Queue中對象進行第二次標記崔挖,如果對象在finalize方法中拯救了自己,即關(guān)聯(lián)上了GCRoots引用鏈庵寞,如把this關(guān)鍵字賦值給其他變量狸相,那么在第二次標記的時候該對象將從“即將回收”的集合中移除,如果對象還是沒有拯救自己捐川,那就會被回收脓鹃。它只能拯救自己一次,第二次就被回收了古沥。此外瘸右,從我們可以得知,一個堆對象的this引用會永遠存在岩齿,在方法體內(nèi)可以將this引用賦值給其他變量太颤,這樣堆中對象就可以被其他變量所引用,即不會被回收.



Java有了GC同樣會出現(xiàn)內(nèi)存泄露問題

1.靜態(tài)集合類像HashMap盹沈、Vector等的使用最容易出現(xiàn)內(nèi)存泄露龄章,這些靜態(tài)變量的生命周期和應用程序一致,所有的對象Object也不能被釋放,因為他們也將一直被Vector等應用著瓦堵。

2.各種連接基协,數(shù)據(jù)庫連接,網(wǎng)絡連接菇用,IO連接等沒有顯示調(diào)用close關(guān)閉澜驮,不被GC回收導致內(nèi)存泄露。

3.監(jiān)聽器的使用惋鸥,在釋放對象的同時沒有相應刪除監(jiān)聽器的時候也可能導致內(nèi)存泄露杂穷。

垃圾回收器負責回收所有無任何引用對象的內(nèi)存空間。

注意:垃圾回收回收的是無任何引用的對象占據(jù)的內(nèi)存空間而不是對象本身卦绣。





 GC注意事項:

  1耐量、只管理內(nèi)存,非托管資源滤港,如文件句柄廊蜒,GDI資源,數(shù)據(jù)庫連接等還需要用戶去管理溅漾。

  2山叮、循環(huán)引用,網(wǎng)狀結(jié)構(gòu)等的實現(xiàn)會變得簡單添履。GC的標志-壓縮算法能有效的檢測這些關(guān)系屁倔,并將不再被引用的網(wǎng)狀結(jié)構(gòu)整體刪除。

  3暮胧、GC通過從程序的根對象開始遍歷來檢測一個對象是否可被其他對象訪問锐借,而不是用類似于COM中的引用計數(shù)方法。

  4往衷、GC在一個獨立的線程中運行來刪除不再被引用的內(nèi)存钞翔。

  5、GC每次運行時會壓縮托管堆炼绘。


GC總結(jié)

[if !supportLists]1.?[endif]JVM堆的大小決定了GC的運行時間嗅战。如果JVM堆的大小超過一定的限度,那么GC的運行時間會很長俺亮。2.對象生存的時間越長驮捍,GC需要的回收時間也越長,影響了回收速度脚曾。3.大多數(shù)對象都是短命的东且,所以,如果能讓這些對象的生存期在GC的一次運行周期內(nèi)本讥,wonderful珊泳!4.應用程序中鲁冯,建立與釋放對象的速度決定了垃圾收集的頻率。5.如果GC一次運行周期超過3-5秒色查,這會很影響應用程序的運行薯演,如果可以,應該減少JVM堆的大小了秧了。6.前輩經(jīng)驗之談:通常情況下跨扮,JVM堆的大小應為物理內(nèi)存的80%。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末验毡,一起剝皮案震驚了整個濱河市衡创,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌晶通,老刑警劉巖璃氢,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異狮辽,居然都是意外死亡一也,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門喉脖,熙熙樓的掌柜王于貴愁眉苦臉地迎上來塘秦,“玉大人,你說我怎么就攤上這事动看。” “怎么了爪幻?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵菱皆,是天一觀的道長。 經(jīng)常有香客問我挨稿,道長仇轻,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任奶甘,我火速辦了婚禮篷店,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘臭家。我一直安慰自己疲陕,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布钉赁。 她就那樣靜靜地躺著蹄殃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪你踩。 梳的紋絲不亂的頭發(fā)上诅岩,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天讳苦,我揣著相機與錄音,去河邊找鬼吩谦。 笑死鸳谜,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的式廷。 我是一名探鬼主播咐扭,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼懒棉!你這毒婦竟也來了草描?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤策严,失蹤者是張志新(化名)和其女友劉穎穗慕,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妻导,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡逛绵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了倔韭。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片术浪。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖寿酌,靈堂內(nèi)的尸體忽然破棺而出胰苏,到底是詐尸還是另有隱情,我是刑警寧澤醇疼,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布硕并,位于F島的核電站,受9級特大地震影響秧荆,放射性物質(zhì)發(fā)生泄漏倔毙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一乙濒、第九天 我趴在偏房一處隱蔽的房頂上張望陕赃。 院中可真熱鬧,春花似錦颁股、人聲如沸么库。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽廊散。三九已至,卻和暖如春梧疲,著一層夾襖步出監(jiān)牢的瞬間允睹,已是汗流浹背运准。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留缭受,地道東北人胁澳。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像米者,于是被迫代替她去往敵國和親韭畸。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

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

  • 1.什么是垃圾回收蔓搞? 垃圾回收(Garbage Collection)是Java虛擬機(JVM)垃圾回收器提供...
    簡欲明心閱讀 89,557評論 17 311
  • 原文閱讀 前言 這段時間懈怠了胰丁,罪過! 最近看到有同事也開始用上了微信公眾號寫博客了喂分,挺好的~給他們點贊锦庸,這博客我...
    碼農(nóng)戲碼閱讀 5,993評論 2 31
  • 1. 垃圾回收的意義在C++中,對象所占的內(nèi)存在程序結(jié)束運行之前一直被占用蒲祈,在明確釋放之前不能分配給其它對象甘萧;而在...
    愛情小傻蛋閱讀 935評論 0 11
  • 這篇文章是我之前翻閱了不少的書籍以及從網(wǎng)絡上收集的一些資料的整理,因此不免有一些不準確的地方梆掸,同時不同JDK版本的...
    高廣超閱讀 15,628評論 3 83
  • 兒童菜扬卷,用兒童的烹飪方式。 今日食譜酸钦,開胃菜系怪得。 兒童的食物,在少油少鹽卑硫,盡量少的調(diào)味料前提下汇恤,通過不一樣的烹飪方...
    寶貝的廚房日記閱讀 279評論 0 4