Java虛擬機——垃圾回收算法與垃圾收集器

在Java運行時的幾個數(shù)據(jù)區(qū)域中惶我,程序計數(shù)器妈倔,虛擬機棧,本地方法棧3個區(qū)域隨著線程而生绸贡,隨線程而滅盯蝴,因此這幾個區(qū)域的內(nèi)存分配和回收具有確定性,不需要過多考慮垃圾回收問題恃轩,因為方法結(jié)束或者線程結(jié)束時结洼,內(nèi)存就回收了黎做。但是方法區(qū)和堆區(qū)不一樣叉跛,一個接口或者實現(xiàn)類所需要的內(nèi)存可能不一樣,一個方法的多個分支需要的內(nèi)存也可能不一樣蒸殿,只有程序運行時才能知道創(chuàng)建哪些對象筷厘,這部分內(nèi)存的分配和回收是動態(tài)的鸣峭。

在進行垃圾回收時候,首先需要判斷哪些對象需要回收酥艳,這就涉及到回收算法的問題摊溶。

一、垃圾回收算法

1.標記-清除算法

標記-清除算法是一種最基礎(chǔ)的垃圾收集算法充石,分為“標記”和“清除”兩步莫换。“標記”階段標記所有需要進行垃圾回收的對象骤铃,標記完成后統(tǒng)一回收被標記的對象。這種算法的不足點在于:

  • 效率問題,標記和清除兩個過程效率都不高邑飒;

  • 空間問題辜王,標記清除后會產(chǎn)生大量不連續(xù)碎片,后續(xù)如果需要為較大對象分配空間撕瞧,則又需觸發(fā)垃圾回收陵叽。

2.復(fù)制算法

為了解決標記-清除算法的效率問題,出現(xiàn)了復(fù)制算法丛版。這種算法把內(nèi)存按照容量劃分為大小相同的兩塊巩掺,每次只是用其中一塊,當這塊內(nèi)存用完了硼婿,就把還存活的對象復(fù)制到另外一塊中锌半,并將這塊的內(nèi)存清理掉,然后使用另外一塊寇漫,當另外一塊內(nèi)存用完了刊殉,再把存活的對象復(fù)制到這塊中,并清理另外一塊內(nèi)存州胳,依次類推记焊。

復(fù)制算法主要用于新生代的回收,在HotSpot虛擬機中栓撞,新生代內(nèi)存劃分為一塊較大的Eden空間遍膜,和兩塊較小的Survivor空間,每次使用Eden空間和其中一塊Survivor空間瓤湘。當進行垃圾回收時瓢颅,會把Eden空間和Survivor空間中存活的對象一次性復(fù)制到另外一塊Survivor空間上,最后清理掉Eden空間和剛才使用過的Survivor空間弛说。HotSpot虛擬機中挽懦,默認情況下Eden空間和Survivor空間的大小比例是8:1,即Eden空間占整個新生代的80%木人,每次新生代中使用的空間為80%+10%=90%信柿,閑置空間10%冀偶。

3.標記-整理算法

復(fù)制算法適用于那種對象存活率較低的場景,在對象存活率較高時渔嚷,使用復(fù)制收集算法意味著需要進行大量復(fù)制进鸠,會使效率降低,同時復(fù)制大量存活對象到另外一塊內(nèi)存形病,意味著需要有足夠大的內(nèi)存來保存這些對象客年,這勢必會降低內(nèi)存使用率。根據(jù)老年代的特點漠吻,有人提出標記-整理算法搀罢,和標記-清除算法不同的是,標記整理算法將存活的對象向一端移動侥猩,然后直接清理掉端邊界之外的內(nèi)存榔至。

4.分代收集算法

目前商業(yè)虛擬機中都使用分代收集算法。一般將Java堆分為新生代和老年代欺劳,新生代進行垃圾收集發(fā)現(xiàn)有大量對象死去唧取,只有少量對象存活,那么就使用復(fù)制算法划提。老年代中對象存活率較高枫弟,使用標記-清除算法或者標記-整理算法。

二鹏往、垃圾收集器

垃圾收集算法提供了內(nèi)存回收的方法論淡诗,垃圾收集器是內(nèi)存回收的方法論。每個廠商對垃圾收集器的實現(xiàn)不一樣伊履,這里主要討論Jdk1.7 Update 14之后的HotSpot虛擬機韩容。這個虛擬機中包含的垃圾收集器有如下7種:

以上收集器之間如果有連線,則表明可以搭配使用唐瀑,虛擬機所處區(qū)域群凶,表示他是新生代收集器還是老年代收集器。

1.Serial收集器

Serial收集器是一種最基本的單線程收集器哄辣,這種收集器工作時请梢,必須停止其他所有工作線程,優(yōu)點在于簡單高效力穗,但體驗很不友好毅弧,目前主要應(yīng)用場合是:虛擬機運行在Client模式下的默認新生代收集。器当窗。

2.ParNew收集器

parNew收集器是Serial收集器的多線程版本够坐,常用參數(shù)設(shè)置:

-XX:+UseConcMarkSweepGC :設(shè)置ParNew為默認的新生代收集器;

-XX:+UseParNewGC :指定使用ParNew為年輕代收集器,強制指定咆霜;

-XX:ParallelGCThreads=n :設(shè)置收集器的線程數(shù)為n。

3.Parallel Scavenge收集器

Parallel Scavenge收集器是一個使用復(fù)制算法的新生代收集器嘶朱,這種收集器的主要目標是達到一個可控制的吞吐量(Throughput蛾坯,CPU用于運行用戶代碼的時間與CPU總消耗時間的比值,即吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間))疏遏。由于與吞吐量關(guān)系密切脉课,故而Parallel Scavenge收集器也稱為“吞吐量優(yōu)先”收集器。常用參數(shù)設(shè)置:

-XX:MaxGCPauseMillis=n :設(shè)置年輕代垃圾收集的最長時間财异;

-XX:GCTimeRatio=n :設(shè)置垃圾收集總可用時長的比例倘零,和吞吐量直接相關(guān);

-XX:+UseAdaptiveSizePolicy :自適應(yīng)大小開關(guān)戳寸,配置該選項之后呈驶,每次GC后會重新計算 Eden、From 和 To 區(qū)的大小疫鹊,計算依據(jù)是 GC 過程中統(tǒng)計的 GC 時間袖瞻、吞吐量、內(nèi)存占用量拆吆,因此設(shè)置此參數(shù)之后就不需要再設(shè)置-XX:SurvivorRatio聋迎、-XX:PretenureSizeThreshold等參數(shù)了。

4.Serial Old收集器

Serial收集器的老年版本枣耀,也是一個單線程收集器霉晕,使用的是“標記-整理”算法,這種收集器的主要意義也是給Client模式下的虛擬機使用捞奕。

5.Parallel Old收集器

Parallel Old收集器是Parallel Scavenge收集器的老年代版本牺堰,使用多線程和“標記-整理”算法。在注重吞吐量以及CPU資源敏感的場合颅围,都可以優(yōu)先考慮Parallel Scavenge收集器和Parallel Old收集器的組合萌焰。

6.CMS收集器

CMS收集器是一種以獲取最短回收停頓時間為目標的收集器。它基于“標記-清除”算法實現(xiàn)谷浅,運作過程相對于其他幾種收集器更復(fù)雜一些扒俯。分為以下四個過程:

  • 初始標記(CMS initial mark):標記一下CG Roots能關(guān)聯(lián)到的對象;

  • 并發(fā)標記(CMS concurrent mark):進行CG Roots Tracing的過程一疯;

  • 重新標記(CMS remark):修正并發(fā)標記期間因用戶程序繼續(xù)運作而導(dǎo)致標記產(chǎn)生變動的那一部分對象的標記記錄撼玄。

  • 并發(fā)清理(CMS concurrent sweep)

CMS 收集器的優(yōu)點在于并發(fā)收集,低停頓墩邀。其缺點在于以下三點

  • CMS收集器對CPU很敏感掌猛,CMS默認回收線程是(CPU數(shù)量+3)/4,當CPU在4個以上時,并發(fā)收集時垃圾收集線程不少于25%的CPU資源荔茬,并隨著CPU數(shù)量增加而下降废膘。但是當CPU不足4個時,CMS對用戶程序的影響就會變得很大慕蔚。

  • CMS收集器無法處理浮動垃圾丐黄。由于CMS收集器并發(fā)清理階段用戶線程還在運行著,伴隨著程序運行就會有垃圾產(chǎn)生孔飒,這部分垃圾在標記過后灌闺,CMS收集器無法在當次收集中清理這些垃圾。

  • 由于CMS收集器是一種基于“標記-清除”算法的收集器坏瞄,這種算法實現(xiàn)的收集器在收集結(jié)束后會有大量不連續(xù)碎片產(chǎn)生桂对。碎片過多時會給大對象分配帶來很大麻煩,往往老年代還有很大空間剩余鸠匀,但是無法找到連續(xù)空間分配當前對象蕉斜,因而不得不提前觸發(fā)Full GC。

7.G1收集器

G1收集器是一款面向服務(wù)端應(yīng)用的垃圾收集器缀棍,與其他收集器相比蛛勉,G1收集器具有如下優(yōu)點:

  • 并發(fā)與并行:G1能充分利用多CPU,多核硬件優(yōu)勢睦柴,使用多個CPU來減少停頓時間诽凌;

  • 分代收集:G1不需要其他收集器配合就能獨立管理整個堆的垃圾收集,且它能采用不同方式去處理新建對象和已經(jīng)存活了一段時間坦敌,熬過多次GC的舊對象以獲得更好的收集效果侣诵。

  • 空間整合:使用G1收集器不會產(chǎn)生內(nèi)存碎片,收集后能提供規(guī)整的可用內(nèi)存狱窘。這種特性有利于程序長時間運行杜顺,分配大對象時候不會因為無法找到連續(xù)內(nèi)存空間而提前觸發(fā)下一次GC.

  • 可預(yù)測的停頓:G1除了追求低停頓,還能建立可預(yù)測的停頓時間模型蘸炸,能讓使用著指定在長度為M毫秒的時間片段內(nèi)躬络,消耗在垃圾收集上的時間不超過N毫秒。

三搭儒、垃圾收集參數(shù)總結(jié)

參數(shù) 描述
UseSerialGC 虛擬機運行在Client模式下的默認值穷当,打開此開關(guān)后,使用Serial+Serial Old的收集器組合進行內(nèi)存回收
UseParNewGC 打開此開關(guān)后淹禾,使用ParNew + Serial Old 的收集器組合進行內(nèi)存回收
UseConcMarkSweepGC 打開此開關(guān)后馁菜,使用ParNew + CMS + Serial Old 的收集器組合進行內(nèi)存回收。Serial Old 收集器將作為CMS收集器出現(xiàn)Concurrent Mode Failure失敗后的后備收集器使用
UseParallelGC 虛擬機運行在Server 模式下的默認值铃岔,打開此開關(guān)后汪疮,使用Parallel Scavenge + Serial Old(PS MarkSweep)的收集器組合進行內(nèi)存回收
UseParallelOldGC 打開此開關(guān)后,使用Parallel Scavenge + Parallel Old 的收集器組合進行內(nèi)存回收
SurvivorRatio 新生代中Eden 區(qū)域與Survivor 區(qū)域的容量比值,默認為8智嚷,代表Eden :Survivor=8∶1
PretenureSizeThreshold 直接晉升到老年代的對象大小卖丸,設(shè)置這個參數(shù)后,大于這個參數(shù)的對象將直接在老年代分配
MaxTenuringThreshold 晉升到老年代的對象年齡盏道。每個對象在堅持過一次Minor GC 之后稍浆,年齡就加1,當超過這個參數(shù)值時就進入老年代
UseAdaptiveSizePolicy 動態(tài)調(diào)整Java 堆中各個區(qū)域的大小以及進入老年代的年齡
HandlePromotionFailure 是否允許分配擔保失敗摇天,即老年代的剩余空間不足以應(yīng)付新生代的整個Eden 和Survivor 區(qū)的所有對象都存活的極端情況
ParallelGCThreads 設(shè)置并行GC 時進行內(nèi)存回收的線程數(shù)
GCTimeRatio GC 時間占總時間的比率,默認值為99恐仑,即允許1% 的GC 時間泉坐。僅在使用Parallel Scavenge 收集器時生效
MaxGCPauseMillis 設(shè)置GC 的最大停頓時間。僅在使用Parallel Scavenge 收集器時生效
CMSInitiatingOccupancyFraction 設(shè)置CMS 收集器在老年代空間被使用多少后觸發(fā)垃圾收集裳仆。默認值為68%腕让,僅在使用CMS 收集器時生效
UseCMSCompactAtFullCollection 設(shè)置CMS 收集器在完成垃圾收集后是否要進行一次內(nèi)存碎片整理。僅在使用CMS 收集器時生效
CMSFullGCsBeforeCompaction 設(shè)置CMS 收集器在進行若干次垃圾收集后再啟動一次內(nèi)存碎片整理歧斟,僅在使用CMS 收集器時生效
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末纯丸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子静袖,更是在濱河造成了極大的恐慌觉鼻,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,743評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件队橙,死亡現(xiàn)場離奇詭異坠陈,居然都是意外死亡,警方通過查閱死者的電腦和手機捐康,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評論 3 385
  • 文/潘曉璐 我一進店門仇矾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人解总,你說我怎么就攤上這事贮匕。” “怎么了花枫?”我有些...
    開封第一講書人閱讀 157,285評論 0 348
  • 文/不壞的土叔 我叫張陵刻盐,是天一觀的道長。 經(jīng)常有香客問我劳翰,道長隙疚,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評論 1 283
  • 正文 為了忘掉前任磕道,我火速辦了婚禮供屉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己伶丐,他們只是感情好悼做,可當我...
    茶點故事閱讀 65,581評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著哗魂,像睡著了一般肛走。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上录别,一...
    開封第一講書人閱讀 49,821評論 1 290
  • 那天朽色,我揣著相機與錄音,去河邊找鬼组题。 笑死葫男,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的崔列。 我是一名探鬼主播梢褐,決...
    沈念sama閱讀 38,960評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼赵讯!你這毒婦竟也來了盈咳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,719評論 0 266
  • 序言:老撾萬榮一對情侶失蹤边翼,失蹤者是張志新(化名)和其女友劉穎鱼响,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體组底,經(jīng)...
    沈念sama閱讀 44,186評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡热押,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,516評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了斤寇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片桶癣。...
    茶點故事閱讀 38,650評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖娘锁,靈堂內(nèi)的尸體忽然破棺而出牙寞,到底是詐尸還是另有隱情,我是刑警寧澤莫秆,帶...
    沈念sama閱讀 34,329評論 4 330
  • 正文 年R本政府宣布间雀,位于F島的核電站,受9級特大地震影響镊屎,放射性物質(zhì)發(fā)生泄漏惹挟。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,936評論 3 313
  • 文/蒙蒙 一缝驳、第九天 我趴在偏房一處隱蔽的房頂上張望连锯。 院中可真熱鬧归苍,春花似錦、人聲如沸运怖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽摇展。三九已至吻氧,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間咏连,已是汗流浹背盯孙。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留祟滴,地道東北人振惰。 一個月前我還...
    沈念sama閱讀 46,370評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像踱启,于是被迫代替她去往敵國和親报账。 傳聞我的和親對象是個殘疾皇子研底,可洞房花燭夜當晚...
    茶點故事閱讀 43,527評論 2 349

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