<深入Java虛擬機>之1.2:垃圾回收機制

? ? 垃圾回收一般是在Java堆,方法區(qū)中進行在张,因為堆中幾乎存放了Java中所有的對象實例杭抠。我們討論的垃圾回收機制一般僅僅作用于jvm堆區(qū)和方法區(qū)泼各,因為它們是thread共享的夷磕,這部分內(nèi)存的分配和回收都是動態(tài)的履肃。

? ? 1??.如何確定某個對象是“垃圾”?

? ? 在所有語言中坐桩,幾乎都要涉及對象是否存活的問題尺棋,比如C++/OC中給對象添加了一個引用計數(shù)機制,當需要的時候绵跷,這個引用的計數(shù)器就會+1膘螟;當引用失效的時候它的計數(shù)器-1;當計數(shù)器=0時碾局,說明該對象不可能再被使用荆残。但是引用計數(shù)機制有個問題,就是很難發(fā)現(xiàn)净当,解決循環(huán)計數(shù)問題:


pic1.B為A的子對象

? ? 程序創(chuàng)建了一個指針内斯,指向了一個計數(shù)為1的A對象,對象A創(chuàng)建了對象B(計數(shù)器也為1)作為組合的子對象像啼。對象A在創(chuàng)建完了俘闯,也會創(chuàng)建對象B,因為依賴忽冻,所以對象A擁有對象B的強引用(指針)≌胬剩現(xiàn)在如果子對象B也有一個指向?qū)ο驛的強引用(指針),那么A的計數(shù)器會變?yōu)?甚颂,如下圖pic2.


pic.2?

? ? 當有一天pointer不需要A對象了(調(diào)用A的析構(gòu)函數(shù))蜜猾,A的counter值變?yōu)?,不過由于對象B的計數(shù)值仍然為1振诬,兩個對象的計數(shù)值!=0,所以都沒有釋放掉蹭睡,造成內(nèi)存泄露。


pic.3 循環(huán)引用的內(nèi)存泄露

? ? C++和OC也都有各種方法解決這個問題赶么,自動化的智能指針/arc技術(shù)等肩豁,但是還是會遇到更棘手的循環(huán)計數(shù)問題。所以Java的用了更加適合辫呻,方便的清理技術(shù)清钥。

? ? Java中采取了 可達性分析法。該方法的基本思想是通過一系列的“GC Roots”對象作為起點進行搜索放闺,如果在“GC Roots”和一個對象之間沒有可達路徑祟昭,則稱該對象是不可達的,不過要注意的是被判定為不可達的對象不一定就會成為可回收對象怖侦。被判定為不可達的對象要成為可回收對象必須至少經(jīng)歷兩次標記過程篡悟,如果在這兩次標記過程中仍然沒有逃脫成為可回收對象的可能性谜叹,則基本上就真的成為可回收對象了“嵩幔可達性分析法具體是如何操作的荷腊,我覺得是圖論中的連通性分析算法。(P.S. GC Roots = jvm棧的引用對象 or 方法區(qū)static對象 or 方法區(qū)常量 or JNI的引用對象)急凰。

? ?2??.典型的垃圾收集算法

? ? 1.Mark-Sweep(標記-清除)算法

? ? 標記-清除算法是最基礎(chǔ)的收集算法女仰,它分為“標記”和“清除”兩個階段:首先標記出所需回收的對象,在標記完成后統(tǒng)一回收掉所有被標記的對象抡锈,它的標記過程其實就是前面的根搜索算法中判定垃圾對象的標記過程疾忍。

回收之前
pic4.標記清除算法,回收之后

這個算法有如下缺點:

? ? -標記和清除過程的效率都不高企孩。

? ? -標記清除后會產(chǎn)生大量不連續(xù)的內(nèi)存碎片锭碳,空間碎片太多可能會導(dǎo)致,當程序在以后的運行過程中需要分配較大對象時無法找到足夠的連續(xù)內(nèi)存而不得不觸發(fā)另一次垃圾收集動作勿璃。


? ? 2.Copying(復(fù)制)算法

? ?復(fù)制算法是針對標記—清除算法的基礎(chǔ)上進行改進而得到的擒抛,它將jvm內(nèi)存按容量分為大小相等的兩塊(但是實際應(yīng)用中不是),每次只使用其中半塊补疑,當這一塊的內(nèi)存用完了歧沪,就將還存活著的對象復(fù)制到另外一塊內(nèi)存上面,然后再把已使用過的內(nèi)存空間一次清理掉莲组。

復(fù)制算法優(yōu)點是 一.簡單诊胞,只需移動棧頂指針,按順序分配內(nèi)存即可锹杈。 二. 高效, 每次只對一塊內(nèi)存進行回收撵孤。三. 不會有內(nèi)存碎片問題。

缺點很明顯竭望,可一次性分配的最大內(nèi)存縮小了一半邪码。


copying 算法

? ? 3.Mark-Compact(標記-整理)算法

? ? 為了解決Copying算法的缺點,充分利用內(nèi)存空間咬清,有了Mark-Compact算法闭专。該算法標記階段和Mark-Sweep一樣,但是在完成標記之后旧烧,它不是直接清理可回收對象影钉,而是將存活對象都向一端移動,然后去除掉端邊界以外的內(nèi)存掘剪。具體過程如下圖所示:

標記-整理算法

? ? 4.Generational Collection(分代收集)算法

? ? 分代收集算法是目前Hotspot垃圾收集器采用的算法平委。它將內(nèi)存劃分為若干個不同的區(qū)域:分為老年代(Tenured Generation)和新生代(Young Generation),在新生代中夺谁,每次垃圾收集時都會發(fā)現(xiàn)有大量對象死去(90%以上)廉赔,只有少量存活愚墓,因此可選用復(fù)制算法來完成收集,不會有太大的復(fù)制開銷昂勉,而老年代中因為對象存活率高、沒有額外空間對它進行分配擔(dān)保扫腺,就必須使用標記—清除算法或標記—整理算法來進行回收岗照。

新生代:新創(chuàng)建的對象都存放在這里。因為大多數(shù)對象很快變得不可達笆环,所以大多數(shù)對象在年輕代中創(chuàng)建攒至,然后消失。這里的垃圾清除叫“minor GC”躁劣。

年代:沒有變得不可達迫吐,存活下來的年輕代對象被復(fù)制到這里。因為它更大的規(guī)模账忘,GC發(fā)生的次數(shù)比在年輕代的少志膀。這里的垃圾清除叫“major GC”(或“full GC”)發(fā)生了。其速度一般會比Minor GC慢10倍以上鳖擒。另外溉浙,如果分配了Direct Memory,在老年代中進行Full GC時蒋荚,會順便清理掉Direct Memory中的廢棄對象戳稽。

永久代(permanent generation)也稱為“方法區(qū)(method area)”,他存儲class對象和字符串常量期升,靜態(tài)變量惊奇。不是永久的存放從老年代存活下來的對象的。在這塊內(nèi)存中有可能發(fā)生垃圾回收播赁。發(fā)生在這里垃圾回收也被稱為Full GC颂郎。

? ?3??. 年輕代組成部分

? ? -對象優(yōu)先在Eden分配。

? ? -大對象直接進入老年代行拢。

? ? -長期存活的對象將進入老年代祖秒。

? ? 年輕代總共有3塊空間,其中2塊為Survivor區(qū)舟奠。


年輕代

? 執(zhí)行順序如下:

絕大多數(shù)新創(chuàng)建的對象分配在Eden區(qū)竭缝。

在Eden區(qū)發(fā)生一次GC后,存活的對象移到其中一個Survivor區(qū)沼瘫。

在Eden區(qū)發(fā)生一次GC后抬纸,對象是存放到Survivor區(qū),這個Survivor區(qū)已經(jīng)存在其他存活的對象耿戚。

一旦一個Survivor區(qū)已滿湿故,存活的對象移動到另外一個Survivor區(qū)阿趁。然后之前那個空間已滿Survivor區(qū)將置為空,沒有任何數(shù)據(jù)坛猪。

經(jīng)過重復(fù)多次這樣的步驟后依舊存活的對象將被移到老年代脖阵。當對象在Survivor區(qū)躲過一次GC的話,其對象年齡便會加1墅茉,默認情況下命黔,如果對象年齡達到15歲,就會移動到老年代中就斤。

?4??.典型的垃圾收集器

1.Serial/Serial Old ?2.ParNew?3.Parallel Scavenge?4.Parallel Old?5.CMS

6. G1:G1是jdk1.7的新的收集器悍募,替換1.5的CMS,其具有并發(fā)洋机,分代收集坠宴,空間整合,可預(yù)測停頓時間模型等特點的新一代收集器技術(shù)绷旗。

代碼來講解:

public class Main

{

? ? public static final int_1MB=1024*1024;

? ? public static voidmain(String[] args)

? ? {

? ? ? ? byte[] a1,a2,a3,a4;

? ? ? ? a1 =new byte[2*_1MB];

? ? ? ? a2 =new byte[2*_1MB];

? ? ? ? a3 =new byte[3*_1MB];

? ? ? ? a4 =new byte[4*_1MB];

? ? }

}

結(jié)果:[GC (Allocation Failure) [PSYoungGen: 5439K->464K(9216K)] 5439K->4568K(19456K), 0.0037039 secs] [Times: user=0.00 sys=0.01, real=0.00 secs]

Heap

PSYoungGen? ? ? total 9216K, used 7922K [0x00000007bf600000, 0x00000007c0000000, 0x00000007c0000000)

eden space 8192K, 91% used [0x00000007bf600000,0x00000007bfd48af8,0x00000007bfe00000)

from space 1024K, 45% used [0x00000007bfe00000,0x00000007bfe74010,0x00000007bff00000)

to? space 1024K, 0% used [0x00000007bff00000,0x00000007bff00000,0x00000007c0000000)

ParOldGen? ? ? total 10240K, used 4104K [0x00000007bec00000, 0x00000007bf600000, 0x00000007bf600000)

object space 10240K, 40% used [0x00000007bec00000,0x00000007bf002020,0x00000007bf600000)

Metaspace? ? ? used 2918K, capacity 4494K, committed 4864K, reserved 1056768K

class space? ? used 324K, capacity 386K, committed 512K, reserved 1048576K

(VM參數(shù)是:-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8)

? ? 從結(jié)果來看喜鼓,分配a4的時候發(fā)生了一次minor gc,這次gc結(jié)果是年輕代從5439K變?yōu)?64K衔肢。a1颠通,a2,a3占用了7MB膀懈,新生代一共10MB顿锰,所以a4要分配進來,必須發(fā)生minor gc启搂,但是此時又發(fā)現(xiàn)survivor區(qū)不能放進a1或者a2或者a3(1MB大小)硼控,所以只好通過分配擔(dān)保機制前轉(zhuǎn)移到老生代去。gc結(jié)束后胳赌,4MB的a4放入老生代牢撼。

? ? 5??.空間分配擔(dān)保

? ? 在發(fā)生gc之前,vm先檢查老年代最大的可用連續(xù)空間是否大于年輕代所有對象總空間疑苫。如果條件成立熏版,minor gc確保成功,如果不成立vm看HandlePromotionFailure設(shè)置的值是否允許擔(dān)保失敗捍掺,如果允許撼短,那么會檢查老年代最大可用的連續(xù)空間是否大于歷次老年代對象的平均值,大于就進行minor gc挺勿,小于就該為full gc曲横。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子禾嫉,更是在濱河造成了極大的恐慌灾杰,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件熙参,死亡現(xiàn)場離奇詭異艳吠,居然都是意外死亡,警方通過查閱死者的電腦和手機孽椰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門讲竿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人弄屡,你說我怎么就攤上這事⌒” “怎么了膀捷?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長削彬。 經(jīng)常有香客問我全庸,道長,這世上最難降的妖魔是什么融痛? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任壶笼,我火速辦了婚禮,結(jié)果婚禮上雁刷,老公的妹妹穿的比我還像新娘覆劈。我一直安慰自己,他們只是感情好沛励,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布责语。 她就那樣靜靜地躺著,像睡著了一般目派。 火紅的嫁衣襯著肌膚如雪坤候。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天企蹭,我揣著相機與錄音白筹,去河邊找鬼。 笑死谅摄,一個胖子當著我的面吹牛徒河,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播送漠,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼虚青,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了螺男?” 一聲冷哼從身側(cè)響起棒厘,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤纵穿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后奢人,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體谓媒,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年何乎,在試婚紗的時候發(fā)現(xiàn)自己被綠了句惯。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡支救,死狀恐怖抢野,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情各墨,我是刑警寧澤指孤,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站贬堵,受9級特大地震影響恃轩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜黎做,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一叉跛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蒸殿,春花似錦筷厘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至楣铁,卻和暖如春玖雁,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背盖腕。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工赫冬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人溃列。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓劲厌,卻偏偏與公主長得像,于是被迫代替她去往敵國和親听隐。 傳聞我的和親對象是個殘疾皇子补鼻,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

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