深入理解JVM2-垃圾收集器和垃圾回收算法

本文主要思考三個問題。
哪些內(nèi)存需要回收妥畏?
什么時候回收邦邦?
如何回收?

對象已死么醉蚁?

1.引用計數(shù)算法

給對象中添加一個引用計數(shù)器燃辖,每當有一個地方引用它,計數(shù)器值就加1网棍;當引用時效的時候黔龟,減一。任何時候計數(shù)器為0的對象就是不可能再被引用的滥玷。(很難解決對象之間相互循環(huán)引用的問題)

2.可達性分析算法

這個算法的基本思路就是通過一系列名為"GC Roots"的對象作為起始點氏身,從這些節(jié)點開始向下搜索,搜索所走過的路徑稱為引用鏈(Reference Chain)惑畴,當一個對象到GC Roots沒有任何引用鏈相連時蛋欣,則證明此對象是不可用的,下圖對象object5, object6, object7雖然有互相判斷如贷,但它們到GC Roots是不可達的陷虎,所以它們將會判定為是可回收對象。


java GC ROOTS的對象包含以下幾種
虛擬機棧中引用的對象
方法區(qū)中類靜態(tài)屬性引用的對象
方法區(qū)中常量引用的對象
本地方法棧種JNI(native方法)引用的對象

引用

1.強引用 一直活著
2.軟引用 還有用但并非必須的對象 活到第二次回收
3.弱引用 非必須對象 活到下一次垃圾收集之前
4.虛引用

生存還是死亡

GC算法

1.標記清除算法

分為標記和清除兩個階段:首先標記出所有需要回收的對象杠袱,在標記完成后統(tǒng)一回收所有被標記的對象泻红。該算法的缺點是效率不高并且會產(chǎn)生不連續(xù)的內(nèi)存碎片。


2.復(fù)制算法

把內(nèi)存空間劃為兩個區(qū)域霞掺,每次只使用其中一個區(qū)域。垃圾回收時讹躯,遍歷當前使用區(qū)域菩彬,把正在使用中的對象復(fù)制到另外一個區(qū)域中缠劝。次算法每次只處理正在使用中的對象,因此復(fù)制成本比較小骗灶,同時復(fù)制過去以后還能進行相應(yīng)的內(nèi)存整理惨恭,不會出現(xiàn)“碎片”問題。優(yōu)點:實現(xiàn)簡單耙旦,運行高效脱羡。缺點:會浪費一定的內(nèi)存。一般新生代采用這種算法


3.標記整理算法

標記階段與標記清除算法一樣免都。但后續(xù)并不是直接對可回收的對象進行清理锉罐,而是讓所有存活對象都想一端移動,然后清理绕娘。優(yōu)點是不會造成內(nèi)存碎片


4.分代收集算法

只是根據(jù)對象存貨周期的不用將內(nèi)存劃分為幾塊脓规。一般是把java堆劃分為新生代和老年代。這樣就可以根據(jù)各個年代的特點采用最適當?shù)氖謾C算法险领。在新生代中侨舆,每次垃圾收集時有大量的對象死亡,只有少量的存在绢陌,那就采用復(fù)制算法挨下,對于老年代,對象存活率高脐湾,沒有額外空間對他進行分配擔(dān)保臭笆,就必須使用“標記-清理”或者“標記-整理”算法來進行回收。

Java中垃圾回收器的類型

Java提供多種類型的垃圾回收器沥割。JVM中的垃圾收集一般都采用“分代收集”耗啦,不同的堆內(nèi)存區(qū)域采用不同的收集算法,主要目的就是為了增加吞吐量或降低停頓時間机杜。

- Serial收集器:新生代收集器帜讲,使用復(fù)制算法,使用一個線程進行GC椒拗,串行似将,其它工作線程暫停。
- ParNew收集器:新生代收集器蚀苛,使用復(fù)制算法在验,Serial收集器的多線程版,用多個線程進行GC堵未,并行腋舌,其它工作線程暫停。使用-XX:+UseParNewGC開關(guān)來控制使用ParNew+Serial Old收集器組合收集內(nèi)存渗蟹;使用-XX:ParallelGCThreads來設(shè)置執(zhí)行內(nèi)存回收的線程數(shù)块饺。
- Parallel Scavenge 收集器:吞吐量優(yōu)先的垃圾回收器赞辩,作用在新生代,使用復(fù)制算法授艰,關(guān)注CPU吞吐量辨嗽,即運行用戶代碼的時間/總時間。使用-XX:+UseParallelGC開關(guān)控制使用Parallel Scavenge+Serial Old收集器組合回收垃圾淮腾。
- Serial Old收集器:老年代收集器糟需,單線程收集器,串行谷朝,使用標記整理算法洲押,使用單線程進行GC,其它工作線程暫停徘禁。
- Parallel Old收集器:吞吐量優(yōu)先的垃圾回收器诅诱,作用在老年代,多線程送朱,并行娘荡,多線程機制與Parallel Scavenge差不錯,使用標記整理算法驶沼,在Parallel Old執(zhí)行時炮沐,仍然需要暫停其它線程。
- CMS(Concurrent Mark Sweep)收集器:老年代收集器回怜,致力于獲取最短回收停頓時間(即縮短垃圾回收的時間)大年,使用標記清除算法,多線程玉雾,優(yōu)點是并發(fā)收集(用戶線程可以和GC線程同時工作)翔试,停頓小。使用-XX:+UseConcMarkSweepGC進行ParNew+CMS+Serial Old進行內(nèi)存回收复旬,優(yōu)先使用ParNew+CMS(原因見Full GC和并發(fā)垃圾回收一節(jié))垦缅,當用戶線程內(nèi)存不足時,采用備用方案Serial Old收集驹碍。
- GI收集器

與GC有關(guān)的JVM參數(shù)

做GC調(diào)優(yōu)需要大量的實踐壁涎,耐心和對項目的分析。我曾經(jīng)參與過高容量志秃,低延遲的電商系統(tǒng)怔球,在開發(fā)中我們需要通過分析造成Full GC的原因來提高系統(tǒng)性能,在這個過程中我發(fā)現(xiàn)做GC的調(diào)優(yōu)很大程度上依賴于對系統(tǒng)的分析浮还,系統(tǒng)擁有怎樣的對象以及他們的平均生命周期竟坛。

舉個例子,如果一個應(yīng)用大多是短生命周期的對象,那么應(yīng)該確保Eden區(qū)足夠大流码,這樣可以減少Minor GC的次數(shù)又官。可以通過-XX:NewRatio來控制新生代和老年代的比例漫试,比如-XX:NewRatio=3代表新生代和老年代的比例為1:3。需要注意的是碘赖,擴大新生代的大小會減少老年代的大小驾荣,這會導(dǎo)致Major GC執(zhí)行的更頻繁,而Major GC可能會造成用戶線程的停頓從而降低系統(tǒng)吞吐量普泡。JVM中可以用NewSize和MaxNewSize參數(shù)來指定新生代內(nèi)存最小和最大值播掷,如果兩個參數(shù)值一樣,那么就相當于固定了新生代的大小撼班。
個人建議歧匈,在做GC調(diào)優(yōu)之前最好深入理解Java中GC機制,推薦閱讀Sun Microsystems提供的有關(guān)GC的文檔砰嘁。這個鏈接可能會對理解GC機制提供一些幫助件炉。下面的圖列出了各個區(qū)可用的一些JVM參數(shù)。


總結(jié)

  • 為了分代垃圾回收矮湘,Java堆內(nèi)存分為3代:新生代斟冕,老年代和永久代。
  • 新的對象實例會優(yōu)先分配在新生代缅阳,在經(jīng)歷幾次Minor GC后(默認15次)磕蛇,還存活的會被移至老年代(某些大對象會直接在老年代分配)。
  • 永久代是否執(zhí)行GC十办,取決于采用的JVM秀撇。
  • Minor GC發(fā)生在新生代,當Eden區(qū)沒有足夠空間時向族,會發(fā)起一次Minor GC呵燕,將Eden區(qū)中的存活對象移至Survivor區(qū)。Major GC發(fā)生在老年代炸枣,當升到老年代的對象大于老年代剩余空間時會發(fā)生Major GC虏等。
  • 發(fā)生Major GC時用戶線程會暫停,會降低系統(tǒng)性能和吞吐量适肠。
  • JVM的參數(shù)-Xmx和-Xms用來設(shè)置Java堆內(nèi)存的初始大小和最大值霍衫。依據(jù)個人經(jīng)驗這個值的比例最好是1:1或者1:1.5。比如侯养,你可以將-Xmx和-Xms都設(shè)為1GB敦跌,或者-Xmx和-Xms設(shè)為1.2GB和1.8GB。
  • Java中不能手動觸發(fā)GC,但可以用不同的引用類來輔助垃圾回收器工作(比如:弱引用或軟引用)柠傍。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末麸俘,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子惧笛,更是在濱河造成了極大的恐慌从媚,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件患整,死亡現(xiàn)場離奇詭異拜效,居然都是意外死亡,警方通過查閱死者的電腦和手機各谚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門紧憾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人昌渤,你說我怎么就攤上這事赴穗。” “怎么了膀息?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵般眉,是天一觀的道長。 經(jīng)常有香客問我履婉,道長煤篙,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任毁腿,我火速辦了婚禮辑奈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘已烤。我一直安慰自己鸠窗,他們只是感情好,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布胯究。 她就那樣靜靜地躺著稍计,像睡著了一般。 火紅的嫁衣襯著肌膚如雪裕循。 梳的紋絲不亂的頭發(fā)上臣嚣,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機與錄音剥哑,去河邊找鬼硅则。 笑死,一個胖子當著我的面吹牛株婴,可吹牛的內(nèi)容都是我干的怎虫。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼大审!你這毒婦竟也來了蘸际?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤徒扶,失蹤者是張志新(化名)和其女友劉穎粮彤,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體姜骡,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡驾诈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了溶浴。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡管引,死狀恐怖士败,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情褥伴,我是刑警寧澤谅将,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站重慢,受9級特大地震影響饥臂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜似踱,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一隅熙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧核芽,春花似錦囚戚、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至哮独,卻和暖如春拳芙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背皮璧。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工舟扎, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人恶导。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓浆竭,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子邦泄,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

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