分代垃圾回收机制及垃圾回收算法
分代垃圾回收
垃圾回收基礎(chǔ)
如下圖所示:
垃圾回收器主要回收堆內(nèi)存,堆內(nèi)存分為:新生代和老年代。
對于回收新生代GC:Minor GC或者叫Young GC。回收老年代的GC叫:Major GC 或者 Old GC.
需要注意Full GC:它不止回收堆內(nèi)存,還會回收方法區(qū)(在JDK1.8 方法區(qū)在元空間;在JDK1.7 方法區(qū)在永久代)
分代回收的理論:
把絕大多數(shù)(98%)的朝生夕死的對象放在新生代
把熬過多次垃圾回收的對象就越難回收放在老年代
那么經(jīng)過上述理論劃分為新生代和老年代,那么垃圾回收算法是怎樣的呢?
在新生代的算法:復(fù)制算法
在老年代的算法:標(biāo)記清除算法、標(biāo)記整理算法
垃圾回收算法
復(fù)制算法
實現(xiàn)簡單、運行高效,沒有內(nèi)存碎片,但是空間利用率只有一半。
復(fù)制算法的原理是什么呢?
需要將內(nèi)存空間一分為二,一半用起來,另一半預(yù)留
如下圖所示:一半的空間用作預(yù)留的空間它在GC之前是不會分配對象的,而另一半會進行分配對象,我們加入下圖中的圓是一個對象,這時候存儲一半空間滿了,就會進行GC垃圾回收。
那么就有了下面的第二步。
將存活的對象復(fù)制到預(yù)留的空間中去,這時候預(yù)留的空間就會進行分配對象,沒有存活的對象直接回收掉,另一半的空間格式化掉當(dāng)做預(yù)留的空間。
我們假設(shè),上述的四個對象,只剩下兩個對象存活,那么這兩個對象會Copy到預(yù)留空間中,之前的空間會直接格式化,那么經(jīng)過第二步變成了如下圖的結(jié)果:
之后new新的對象會放在當(dāng)前的空間,如果空間又滿了,就會繼續(xù)走第二步。
下面我們來看一下堆區(qū)的新生代是如何利用復(fù)制算法?
Eden區(qū)的來源:Appel式回收、提高空間利用率和空間分配擔(dān)保 Eden區(qū)的來源,主要是解決上述復(fù)制算法理論的基礎(chǔ),空間利用率只有一半的問題 Eden 區(qū)占80% from區(qū)10% to區(qū)10% 幾乎所有的對象優(yōu)先在Eden區(qū)分配,當(dāng)Eden區(qū)滿了之后,就會判斷對象存活(98%的對象是朝生夕死的),垃圾回收,存活對象進入From區(qū),之后Eden就會全部清空,為下一次分配對象做準(zhǔn)備。當(dāng)Eden區(qū)又滿了,就會繼續(xù)觸發(fā)垃圾回收,Eden存活的對象就會放在To區(qū),同時From區(qū)的對象經(jīng)過可達(dá)性分析存活的對象也會進入到To區(qū)。可能只看文字看的似懂非懂,下面我通過畫圖來展示。
Eden 區(qū)幾乎所有對象會在此分配,一般大對象是直接進入老年代
當(dāng)Eden區(qū)空間滿了以后,就會觸發(fā)垃圾回收,根據(jù)根可達(dá)判斷存活的對象,將存活的對象分配到From區(qū),同時Eden區(qū)清空,為一下次分配對象做準(zhǔn)備
當(dāng)Eden區(qū)空間又滿了,觸發(fā)GC,根據(jù)根可達(dá)判斷存活對象,將存活的對象復(fù)制到To區(qū),同時From區(qū)的對象經(jīng)過可達(dá)性分析存活的對象復(fù)制到To區(qū)
當(dāng)Eden區(qū)又滿了,就會觸發(fā)同樣的步驟,存活的對象會在From和To之間來回復(fù)制。
經(jīng)過上述n個步驟,我們知道From區(qū)和To區(qū)只有10%的空間,當(dāng)Eden區(qū)滿了,而這時要將存活的對象移到To區(qū),然而經(jīng)過n個步驟存活的對象太多了超過了10%的預(yù)留空間,這時候就會觸發(fā)空間分配擔(dān)保操作, 就會進入老年代區(qū)域中。同時JVM還有一個優(yōu)化的操作。(在新生代的對象沒經(jīng)過一次GC就會增加分代年齡,當(dāng)分代年齡達(dá)到15(不是絕對的)對象還存活,就會進入老年代區(qū))
通過上述圖示,應(yīng)該將新生代的復(fù)制算法講解清楚了。新生代的復(fù)制算法利用Eden區(qū)將空間利用率降低到了只有10%是預(yù)留的,其他的空間都是利用的。
注意:如果是個大對象就會直接進入老年代。
標(biāo)記清除算法(Mark-Sweep)
位置不連續(xù),產(chǎn)生碎片;效率略低,兩遍掃描;空間利用率100%
掃描空間根據(jù)可達(dá)性分析標(biāo)記可回收的對象,打上標(biāo)記。
掃描空間根據(jù)標(biāo)記可回收的對象,進行清除。
標(biāo)記清除算法會導(dǎo)致內(nèi)存不連續(xù),產(chǎn)生碎片。
假設(shè)一個對象占用的內(nèi)存空間占據(jù)5個格子,但是回收后的空間,不連續(xù)的沒有可存放的位置了,分配不下去了。
也就有了標(biāo)記-整理算法,對內(nèi)存不連續(xù)的內(nèi)存空間進行整理
標(biāo)記整理算法(Mark-Compact)
沒有內(nèi)存碎片,效率偏低,兩遍掃描,指針需要調(diào)整。
標(biāo)記整理算法的效率是偏低的,因為需要移動指針,假設(shè)一個對象的指針是在1號,而通過標(biāo)記整理指針變成了10號位置,那么對應(yīng)的引用就需要改變,方法要改變那么全部的線程要暫停把對應(yīng)的引用進行更新。
第一次掃描,標(biāo)記可回收的對象,這個和標(biāo)記清除算法的第一步類似
第二次掃描,清除可回收的對象,整理內(nèi)存空間。(這一步比標(biāo)記清除算法多了一步空間整理,使空間連續(xù))
JVM中常見的垃圾回收器
單線程垃圾回收器
多線程并行垃圾回收器
并發(fā)垃圾回收器
| 回收器 | 回收對象和算法 | 回收器類型 |
|---|---|---|
| Serial | 新生代,復(fù)制算法 | 單線程(串行) |
| Parallel Scavenge | 新生代,復(fù)制算法 | 并行的多線程回收器 |
| ParNew | 新生代,復(fù)制算法 | 并行的多線程收集器 |
| Serial Old | 老年代,標(biāo)記整理算法 | 單線程(串行) |
| Parallel Old | 老年代,標(biāo)記整理算法 | 并行的多線程回收器 |
| CMS | 老年代,標(biāo)記清除算法 | 并發(fā)的多線程回收器 |
| G1 | 跨新生代和老年代:標(biāo)記整理+化整為零 | 并發(fā)的多線程回收器 |
單線程收集 Serial/Serial Old :
參數(shù):UseSerialGC 最古老的單線程、獨占。只適用于幾十兆到一兩百兆,每次垃圾回收都會停頓 STW(Stop The World) ,停止業(yè)務(wù)線程,等垃圾回收完畢之后更新業(yè)務(wù)線程的引用。
如下圖,單線程收集
當(dāng)GC的時候會暫停所有用戶線程,啟動GC線程
STW(Stop The World):垃圾回收器的發(fā)展的重點就是降低STW。隨著垃圾回收器的發(fā)展也就有了多線程的垃圾回收器和并發(fā)的垃圾回收器
多線程收集 Parallel Scavenge/Parallel Old
Parallel Scavenge/Parallel Old 是JDK1.8默認(rèn)的垃圾收集器
Parallel Scavenge:回收新生代
Parallel Old:回收老年代
垃圾回收器是多線程的提高回收的效率
下面是相關(guān)的參數(shù):
吞吐量=運行用戶代碼時間/(運行用戶代碼時間+垃圾收集時間)
UseAdaptiveSizePollcy : 完成最大的吞吐量
Parallel Scavenge/Parallel Old 垃圾收集器追求的是吞吐量,但是STW并沒有減少多少。
STW會帶來哪些危害?
假設(shè)STW垃圾回收暫停了10s 而 請求響應(yīng)只用了1s 那么總共請求 1s + 10s= 11s
為了減少STW的時間,于是就有了并發(fā)垃圾回收器。
并發(fā)垃圾回收器 CMS(Concurrent Mark Sweep)/ParNew
CMS 主要針對老年代的垃圾回收器,主要是降低STW。由于Parallel Scavenge是新生代的垃圾回收器,但是Parallel Scavenge追求的吞吐量,并不能降低STW,于是就有了ParNew 來和CMS配對,ParNew 負(fù)責(zé)新生代、CMS 負(fù)責(zé)老年代。
CMS 采用的是標(biāo)記清除算法,那么CMS是如何并發(fā)標(biāo)記清除呢?看下面:
初始標(biāo)記: 標(biāo)記GC roots有直接關(guān)系的對象,標(biāo)記速度會非常快。這時候就會暫停業(yè)務(wù)線程
并發(fā)標(biāo)記: 進行GC Roots Tracing的過程,標(biāo)記可回收的對象,而這時候的標(biāo)記量會很大,時間會很長所以采取并發(fā)的方式,讓業(yè)務(wù)線程和并發(fā)標(biāo)記一起跑,不會暫停業(yè)務(wù)線程。GC和用戶線程同時跑,肯定會有一些偏差,中間還有一些變化和沒有標(biāo)記的,所以就有了重新標(biāo)記
重新標(biāo)記:為了修正并發(fā)標(biāo)記期間因用戶程序繼續(xù)運作而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分的標(biāo)記記錄,這個過程會比初始標(biāo)記長一些,但是遠(yuǎn)比并發(fā)標(biāo)記端,所以會暫停所有用戶線程(STW),標(biāo)記剩余的,這段是時間較短的。
并發(fā)清除:在上述講到的標(biāo)記清除算法中,需要挨個刪除標(biāo)記的可回收的對象,這種操作肯定時間比較長,所以使用并發(fā)清除讓用戶和GC同時運行,
重置線程
在并發(fā)標(biāo)記和并發(fā)清除可以很有效的降低STW。
CMS是一款優(yōu)秀的收集器,它的主要優(yōu)點在名字上已經(jīng)體現(xiàn)出來了:并發(fā)收集、低停頓
CMS的缺點:
對CPU資源敏感:面向并發(fā)設(shè)計的程序都對CPU資源比較敏感,在并發(fā)階段雖然不會導(dǎo)致用戶線程停頓,但是會占用一部分線程而導(dǎo)致應(yīng)用程序變慢,總吞吐量會降低。CMS默認(rèn)啟動的回收線程數(shù)時(CPU數(shù)量+3)/4,也就是當(dāng)CPU在4個以上時,并發(fā)回收時垃圾收集線程不少于25%的CPU資源,當(dāng)CPU不足4個時,CMS對用戶程序的影響就很可能變得很大。
無法處理浮動垃圾:由于CMS并發(fā)清理階段用戶線程還在運行著,伴隨程序運行自然就還會有新的垃圾不斷產(chǎn)生。這一部分垃圾出現(xiàn)在標(biāo)記過程之后,CMS無法再次收集處理他們,只好留待下一次GC時再清理掉。假如老年代100m,當(dāng)?shù)搅?2m觸發(fā)垃圾回收,而這時候老年代有占用了90m,而這時候產(chǎn)生了20m的浮動垃圾如何處理呢?就會采用Serial Old來進行替代
標(biāo)記清除算法導(dǎo)致的內(nèi)存碎片,當(dāng)空間碎片過多時,將會給大對象分配帶來很大麻煩,往往會出現(xiàn)老年代空間剩余,但無法找到足夠大連續(xù)空間來分配當(dāng)前對象。
CMS 的垃圾回收器帶來的問題還是非常多的。維護起來非常麻煩的,所以在JDK1.7 JDK1.8都沒有將CMS設(shè)置成默認(rèn)的垃圾回收器。但是CMS是并發(fā)標(biāo)記的垃圾回收器的基石,雖然有很多問題,但是CMS的并發(fā)標(biāo)記思想才有了后面G1的優(yōu)秀的垃圾回收器
為什么CMS不使用標(biāo)記整理算法?
如果過采用標(biāo)記整理算法,需要清理和整理的同時用戶線程還會跑,而標(biāo)記整理涉及到了指針的調(diào)整,那么CMS還得在多做一步,而使用標(biāo)記清除只需要標(biāo)記的清除就可以了。
在CMS之后,JVM推出了G1垃圾回收器。
G1(Garbage First) 垃圾回收器
G1:追求停頓時間;Region區(qū);篩選回收;可預(yù)測停頓;復(fù)制和標(biāo)記整理算法
G1 將整個堆區(qū)化整為零,有了Region區(qū):
E和S是新生代;
O 是老年代
H 表示大對象也是老年代
G1 垃圾回收器的運作分為如下幾個步驟:
初始標(biāo)記: 僅僅只是標(biāo)記一下GC Roots 能直接關(guān)聯(lián)到的對象,并且修改TAMS(Nest Top Mark Start)的值,讓下一階段用戶程序并發(fā)運行時,能在正確可以的Region中創(chuàng)建對象,此階段需要停頓線程,但耗時很短。
并發(fā)標(biāo)記: 從GC Root 開始對堆中對象進行可達(dá)性分析,找到存活對象,此階段耗時較長,但可與用戶程序并發(fā)執(zhí)行。
最終標(biāo)記: 為了修正在并發(fā)標(biāo)記期間因用戶程序繼續(xù)運作而導(dǎo)致標(biāo)記產(chǎn)生變動的那一部分標(biāo)記記錄,虛擬機將這段時間對象變化記錄在線程的Remembered Set Logs里面,最終標(biāo)記階段需要把Remembered Set Logs的數(shù)據(jù)合并到Remembered Set中,這階段需要停頓線程,但是可并行執(zhí)行。
篩選回收 :首先對各個Region中的回收價值和成本進行排序,根據(jù)用戶所期望的GC 停頓是時間來制定回收計劃。此階段其實也可以做到與用戶程序一起并發(fā)執(zhí)行,但是因為只回收一部分Region,時間是用戶可控制的,而且停頓用戶線程將大幅度提高收集效率。
開啟G1垃圾收集器的參數(shù):
作者:donleo123
出處:https://www.cnblogs.com/donleo123/
本文如對您有幫助,還請多推薦下此文,如有錯誤歡迎指正,相互學(xué)習(xí),共同進步。
總結(jié)
以上是生活随笔為你收集整理的分代垃圾回收机制及垃圾回收算法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iOS网络编程开发-数据加密
- 下一篇: HDU -2546饭卡(01背包+贪心)