Java垃圾回收(GC)機(jī)制

為什么需要垃圾回收

如果不進(jìn)行垃圾回收搁胆,內(nèi)存遲早都會(huì)被消耗空,因?yàn)槲覀冊(cè)诓粩嗟姆峙鋬?nèi)存空間而不進(jìn)行回收渠旁。除非內(nèi)存無(wú)限大船逮,我們可以任性的分配而不回收,但是事實(shí)并非如此挖胃。所以,垃圾回收是必須的酱鸭。

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

哪些內(nèi)存需要回收是垃圾回收機(jī)制第一個(gè)要考慮的問(wèn)題烁登,所謂“要回收的垃圾”無(wú)非就是那些不可能再被任何途徑使用的對(duì)象。那么如何找到這些對(duì)象饵沧?

可達(dá)性分析法赌躺,這個(gè)算法的基本思想是通過(guò)一系列稱(chēng)為“GC Roots”的對(duì)象作為起始點(diǎn),從這些節(jié)點(diǎn)向下搜索礼患,搜索所走過(guò)的路徑稱(chēng)為引用鏈,當(dāng)一個(gè)對(duì)象到GC Roots沒(méi)有任何引用鏈(即GC Roots到對(duì)象不可達(dá))時(shí)讶泰,則證明此對(duì)象是不可用的。

如何選取GCRoots對(duì)象呢码泞?在Java語(yǔ)言中,可以作為GCRoots的對(duì)象包括下面幾種:
(1) 虛擬機(jī)棧(棧幀中的局部變量區(qū)余寥,也叫做局部變量表)中引用的對(duì)象。
(2) 方法區(qū)中的類(lèi)靜態(tài)屬性引用的對(duì)象宋舷。
(3) 方法區(qū)中常量引用的對(duì)象。
(4) 本地方法棧中JNI(Native方法)引用的對(duì)象祝蝠。
下面給出一個(gè)GCRoots的例子,如下圖绎狭,為GCRoots的引用鏈。


圖1

由圖可知喇聊,obj8蹦狂、obj9、obj10都沒(méi)有到GCRoots對(duì)象的引用鏈凯楔,即便obj9和obj10之間有引用鏈,他們還是會(huì)被當(dāng)成垃圾處理啊研,可以進(jìn)行回收。

四種引用狀態(tài)

在JDK1.2之前,Java中引用的定義很傳統(tǒng):如果引用類(lèi)型的數(shù)據(jù)中存儲(chǔ)的數(shù)值代表的是另一塊內(nèi)存的起始地址削解,就稱(chēng)這塊內(nèi)存代表著一個(gè)引用。這種定義很純粹氛驮,但是太過(guò)于狹隘,一個(gè)對(duì)象只有被引用或者沒(méi)被引用兩種狀態(tài)盏缤。我們希望描述這樣一類(lèi)對(duì)象:當(dāng)內(nèi)存空間還足夠時(shí),則能保留在內(nèi)存中唉铜;如果內(nèi)存空間在進(jìn)行垃圾收集后還是非常緊張律杠,則可以拋棄這些對(duì)象竞惋。很多系統(tǒng)的緩存功能都符合這樣的應(yīng)用場(chǎng)景灰嫉。在JDK1.2之后,Java對(duì)引用的概念進(jìn)行了擴(kuò)充讼撒,將引用分為強(qiáng)引用、軟引用根盒、弱引用、虛引用4種郑象,這4種引用強(qiáng)度依次減弱。

1厂榛、強(qiáng)引用
代碼中普遍存在的類(lèi)似"Object obj = new Object()"這類(lèi)的引用,只要強(qiáng)引用還存在辈双,垃圾收集器永遠(yuǎn)不會(huì)回收掉被引用的對(duì)象。
2湃望、軟引用
描述有些還有用但并非必需的對(duì)象痰驱。在系統(tǒng)將要發(fā)生內(nèi)存溢出異常之前,將會(huì)把這些對(duì)象列進(jìn)回收范圍進(jìn)行二次回收担映。如果這次回收還沒(méi)有足夠的內(nèi)存,才會(huì)拋出內(nèi)存溢出異常蝇完。Java中的類(lèi)SoftReference表示軟引用。
3氢架、弱引用
描述非必需對(duì)象。被弱引用關(guān)聯(lián)的對(duì)象只能生存到下一次垃圾回收之前岖研,垃圾收集器工作之后警检,無(wú)論當(dāng)前內(nèi)存是否足夠硬纤,都會(huì)回收掉只被弱引用關(guān)聯(lián)的對(duì)象。Java中的類(lèi)WeakReference表示弱引用筝家。
4邻辉、虛引用
這個(gè)引用存在的唯一目的就是在這個(gè)對(duì)象被收集器回收時(shí)收到一個(gè)系統(tǒng)通知,被虛引用關(guān)聯(lián)的對(duì)象值骇,和其生存時(shí)間完全沒(méi)關(guān)系。Java中的類(lèi)PhantomReference表示虛引用道伟。


圖2
JAVA什么時(shí)候執(zhí)行垃圾回收

JAVA的垃圾回收分為三個(gè)區(qū)域:新生代使碾,老年代,永久代票摇。
1、新生代:

  • Eden(伊甸園)區(qū)是新對(duì)象分配內(nèi)存的地方矢门,由于堆是所有線程共享的,因此在堆上分配內(nèi)存需要加鎖隔躲。而Sun JDK為提升效率,會(huì)為每個(gè)新建的線程在Eden上分配一塊獨(dú)立的空間由該線程獨(dú)享蹭越,這塊空間稱(chēng)為T(mén)LAB(Thread Local Allocation Buffer)教届。在TLAB上分配內(nèi)存不需要加鎖驾霜,因此JVM在給線程中的對(duì)象分配內(nèi)存時(shí)會(huì)盡量在TLAB上分配。如果對(duì)象過(guò)大或TLAB用完强霎,則仍然在堆上進(jìn)行分配。如果Eden區(qū)內(nèi)存也用完了城舞,則會(huì)進(jìn)行一次Minor GC(young GC)。
  • Survivor from to
    Survivor 區(qū)有兩塊家夺,一塊稱(chēng)為from區(qū),另一塊為to區(qū)拉馋,這兩個(gè)區(qū)是相對(duì)的,在發(fā)生一次Minor GC后煌茴,from區(qū)就會(huì)和to區(qū)互換。在發(fā)生Minor GC時(shí)蔓腐,Eden區(qū)和Survivor from區(qū)會(huì)把一些仍然存活的對(duì)象復(fù)制進(jìn)Survivor to區(qū),并清除內(nèi)存散罕。Survivor to區(qū)會(huì)把一些存活得足夠舊的對(duì)象移至年老代。
    2笨使、老年代:
    老年代里存放的都是存活時(shí)間較久的僚害,大小較大的對(duì)象,因此年老代使用標(biāo)記整理算法萨蚕。當(dāng)年老代容量滿的時(shí)候,會(huì)觸發(fā)一次Major GC(full GC)岳遥,回收年老代和年輕代中不再被使用的對(duì)象資源。
    3派继、 永久代
    在JDK8之前的HotSpot虛擬機(jī)中,類(lèi)的這些“永久的”數(shù)據(jù)存放在一個(gè)叫做永久代的區(qū)域驾窟。永久代一段連續(xù)的內(nèi)存空間认轨,我們?cè)贘VM啟動(dòng)之前可以通過(guò)設(shè)置-XX:MaxPermSize的值來(lái)控制永久代的大小,32位機(jī)器默認(rèn)的永久代的大小為64M,64位的機(jī)器則為85M杉畜。永久代的垃圾回收和老年代的垃圾回收是綁定的,一旦其中一個(gè)區(qū)域被占滿此叠,這兩個(gè)區(qū)都要進(jìn)行垃圾回收匾荆。但是有一個(gè)明顯的問(wèn)題,由于我們可以通過(guò)?XX:MaxPermSize 設(shè)置永久代的大小牙丽,一旦類(lèi)的元數(shù)據(jù)超過(guò)了設(shè)定的大小,程序就會(huì)耗盡內(nèi)存烤芦,并出現(xiàn)內(nèi)存溢出錯(cuò)誤OutOfMemoryError(OOM)。這里值得注意的是铜涉,JDK8移除了永久代。


    圖3

    總結(jié)一下:

  • 一個(gè)對(duì)象實(shí)例化時(shí)芙代,先去看伊甸園有沒(méi)有足夠的空間;
  • 如果有纹烹,不進(jìn)行垃圾回收召边,對(duì)象直接在伊甸園存儲(chǔ);
  • 如果伊甸園內(nèi)存已滿隧熙,會(huì)進(jìn)行一次minor gc;然后再進(jìn)行判斷伊甸園中的內(nèi)存是否足夠;
  • 如果不足贞盯,則去看存活區(qū)的內(nèi)存是否足夠;如果內(nèi)存足夠,把伊甸園部分活躍對(duì)象保存在存活區(qū)躏敢,然后把對(duì)象保存在伊甸園。
  • 如果內(nèi)存不足,向老年代發(fā)送請(qǐng)求,查詢老年代的內(nèi)存是否足夠蛾扇;
  • 如果老年代內(nèi)存足夠,將部分存活區(qū)的活躍對(duì)象存入老年代坟漱。然后把伊甸園的活躍對(duì)象放入存活區(qū),對(duì)象依舊保存在伊甸園芋齿。
  • 如果老年代內(nèi)存不足成翩,會(huì)進(jìn)行一次full gc,之后老年代會(huì)再進(jìn)行判斷內(nèi)存是否足夠麻敌。如果足夠,同上术羔;如果不足,會(huì)拋出OutOfMemory Error级历。

需要注意的是,GC雖然可以進(jìn)行內(nèi)存空間的釋放玩讳,但同時(shí)頻繁的GC一定會(huì)影響性能,GC發(fā)生的頻率越低锋边,你的系統(tǒng)就越高效。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末豆巨,一起剝皮案震驚了整個(gè)濱河市掐场,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌熊户,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蝗罗,死亡現(xiàn)場(chǎng)離奇詭異艇棕,居然都是意外死亡沼琉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén)打瘪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)傻昙,“玉大人,你說(shuō)我怎么就攤上這事妆档。” “怎么了过吻?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵纤虽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我逼纸,道長(zhǎng),這世上最難降的妖魔是什么杰刽? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮滓鸠,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘糜俗。我一直安慰自己,他們只是感情好悠抹,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布扩淀。 她就那樣靜靜地躺著,像睡著了一般驻谆。 火紅的嫁衣襯著肌膚如雪庆聘。 梳的紋絲不亂的頭發(fā)上勺卢,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼织盼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛沥邻,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播唐全,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼邮利!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起延届,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎厕吉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體头朱,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡龄减,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了欺殿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡程拭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恃鞋,到底是詐尸還是另有隱情崖媚,我是刑警寧澤恤浪,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站荠呐,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏泥张。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一媚创、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧钞钙,春花似錦、人聲如沸芒炼。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)弧关。三九已至盅安,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間世囊,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工蝙寨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嗤瞎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓贝奇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親掉瞳。 傳聞我的和親對(duì)象是個(gè)殘疾皇子浪漠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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

  • 哪些內(nèi)存需要回收霎褐? 哪些內(nèi)存需要回收是垃圾回收機(jī)制第一個(gè)要考慮的問(wèn)題,所謂“要回收的垃圾”無(wú)非就是那些不可能再被任...
    待汝豪杰只是凡夫閱讀 557評(píng)論 0 1
  • 1.什么是垃圾回收响谓? 垃圾回收(Garbage Collection)是Java虛擬機(jī)(JVM)垃圾回收器提供...
    簡(jiǎn)欲明心閱讀 89,412評(píng)論 17 311
  • 本文由作者自行翻譯省艳,未經(jīng)作者授權(quán)歌粥,不得隨意轉(zhuǎn)發(fā)。后續(xù)作者會(huì)陸續(xù)發(fā)布一系列關(guān)于JVM內(nèi)存管理的文章土居,敬請(qǐng)期待枣购。 1棉圈、...
    猿學(xué)堂閱讀 1,344評(píng)論 0 50
  • 在Java虛擬機(jī)中,對(duì)象和數(shù)組的內(nèi)存都是在堆中分配的分瘾,垃圾收集器主要回收的內(nèi)存就是再堆內(nèi)存中。如果在Java程序運(yùn)...
    xiaoyanger閱讀 493評(píng)論 1 7
  • 原文閱讀 前言 這段時(shí)間懈怠了德召,罪過(guò)汽纤! 最近看到有同事也開(kāi)始用上了微信公眾號(hào)寫(xiě)博客了上岗,挺好的~給他們點(diǎn)贊蕴坪,這博客我...
    碼農(nóng)戲碼閱讀 5,948評(píng)論 2 31