JVM垃圾回收算法 总结及汇总
先看一眼JVM虛擬機(jī)運(yùn)行時(shí)的內(nèi)存模型:
?
1.方法區(qū) Perm(永久代、非堆)
2.虛擬機(jī)棧
3.本地方法棧 (Native方法)
4.堆
5.程序計(jì)數(shù)器
?
1 首先的問(wèn)題是:jvm如何知道那些對(duì)象需要回收 ?
目前兩種標(biāo)識(shí)算法、三種回收算法、兩種清除算法、三種收集器
- 引用計(jì)數(shù)法
每個(gè)對(duì)象上都有一個(gè)引用計(jì)數(shù),對(duì)象每被引用一次,引用計(jì)數(shù)器就+1,對(duì)象引用被釋放,引用計(jì)數(shù)器-1,直到對(duì)象的引用計(jì)數(shù)為0,對(duì)象就標(biāo)識(shí)可以回收
這個(gè)可以用數(shù)據(jù)算法中的圖形表示,對(duì)象A-對(duì)象B-對(duì)象C 都有引用,所以不會(huì)被回收,對(duì)象B由于沒(méi)有被引用,沒(méi)有路徑可以達(dá)到對(duì)象B,對(duì)象B的引用計(jì)數(shù)就就是0,對(duì)象B就會(huì)被回收。
?
?
但是這個(gè)算法有明顯的缺陷,對(duì)于循環(huán)引用的情況下,循環(huán)引用的對(duì)象就不會(huì)被回收。例如下圖:對(duì)象A,對(duì)象B 循環(huán)引用,沒(méi)有其他的對(duì)象引用A和B,則A和B 都不會(huì)被回收。
?
- root搜索算法
這種算法目前定義了幾個(gè)root,也就是這幾個(gè)對(duì)象是jvm虛擬機(jī)不會(huì)被回收的對(duì)象,所以這些對(duì)象引用的對(duì)象都是在使用中的對(duì)象,這些對(duì)象未使用的對(duì)象就是即將要被回收的對(duì)象。簡(jiǎn)單就是說(shuō):如果對(duì)象能夠達(dá)到root,就不會(huì)被回收,如果對(duì)象不能夠達(dá)到root,就會(huì)被回收。
如下圖:對(duì)象D訪問(wèn)不到根對(duì)象,所以就會(huì)被回收
以下對(duì)象會(huì)被認(rèn)為是root對(duì)象:
- 被啟動(dòng)類(lèi)(bootstrap加載器)加載的類(lèi)和創(chuàng)建的對(duì)象
- jvm運(yùn)行時(shí)方法區(qū)類(lèi)靜態(tài)變量(static)引用的對(duì)象
- jvm運(yùn)行時(shí)方法去常量池引用的對(duì)象
- jvm當(dāng)前運(yùn)行線程中的虛擬機(jī)棧變量表引用的對(duì)象
- 本地方法棧中(jni)引用的對(duì)象
由于這種算法即使存在互相引用的對(duì)象,但如果這兩個(gè)對(duì)象無(wú)法訪問(wèn)到根對(duì)象,還是會(huì)被回收。如下圖:對(duì)象C和對(duì)象D互相引用,但是由于無(wú)法訪問(wèn)根,所以會(huì)被回收。
jvm在確定是否回收的對(duì)象的時(shí)候采用的是root搜索算法來(lái)實(shí)現(xiàn)。
在root搜索算法的里面,我們說(shuō)的引用這里都指定的是強(qiáng)引用關(guān)系。所謂強(qiáng)引用關(guān)系,就是通過(guò)用new 方式創(chuàng)建的對(duì)象,并且顯示關(guān)聯(lián)的對(duì)象
[java]?view plain?copy以上就是代表的是強(qiáng)引用關(guān)系,變量obj 強(qiáng)引用了 Object的一個(gè)對(duì)象。
java里面有四種應(yīng)用關(guān)系,從強(qiáng)到弱分別為:
Strong Reference(強(qiáng)引用) –>Weak Reference (弱引用) -> Soft Reference(軟引用) – > Phantom Reference(引用)
?
Strong Reference : 只有在引用對(duì)象root不可達(dá)的情況下才會(huì)標(biāo)識(shí)為可回收,垃圾回收才可能進(jìn)行回收
Weak Reference :即使在root算法中 其引用的對(duì)象root可達(dá)到,但是如果jvm堆內(nèi)存 不夠的時(shí)候,還是會(huì)被回收。
Soft Reference : 無(wú)論其引用的對(duì)象是否root可達(dá),在響應(yīng)內(nèi)存需要時(shí),由垃圾回收判斷是否需要回收。
Phantom Reference :在回收器確定其指示對(duì)象可另外回收之后,被加入垃圾回收隊(duì)列.
?
?
-
標(biāo)記-清除
標(biāo)記清除的算法最簡(jiǎn)單,主要是標(biāo)記出來(lái)需要回收的對(duì)象,然后然后把這些對(duì)象在內(nèi)存的信息清除。如何標(biāo)記需要回收的對(duì)象,在上一篇文章里面已經(jīng)有說(shuō)明。
?
-
標(biāo)記-清除-壓縮
這個(gè)算法是在標(biāo)記-清除的算法之上進(jìn)行一下壓縮空間,重新移動(dòng)對(duì)象的過(guò)程。因?yàn)闃?biāo)記清除算法會(huì)導(dǎo)致很多的留下來(lái)的內(nèi)存空間碎片,隨著碎片的增多,嚴(yán)重影響內(nèi)存讀寫(xiě)的性能,所以在標(biāo)記-清除之后,會(huì)對(duì)內(nèi)存的碎片進(jìn)行整理。最簡(jiǎn)單的整理就是把對(duì)象壓縮到一邊,留出另一邊的空間。由于壓縮空間需要一定的時(shí)間,會(huì)影響垃圾收集的時(shí)間。
?
-
標(biāo)記-清除-復(fù)制
這個(gè)算法是吧內(nèi)存分配為兩個(gè)空間,一個(gè)空間(A)用來(lái)負(fù)責(zé)裝載正常的對(duì)象信息,,另外一個(gè)內(nèi)存空間(B)是垃圾回收用的。每次把空間A中存活的對(duì)象全部復(fù)制到空間B里面,在一次性的把空間A刪除。這個(gè)算法在效率上比標(biāo)記-清除-壓縮高,但是需要兩塊空間,對(duì)內(nèi)存要求比較大,內(nèi)存的利用率比較低。適用于短生存期的對(duì)象,持續(xù)復(fù)制長(zhǎng)生存期的對(duì)象則導(dǎo)致效率降低
?
由于現(xiàn)在的處理器都是多核的,處理器的性能得到了極大的提升,所以在此基礎(chǔ)上有產(chǎn)生了幾種垃圾收集算法。主要包括兩種算法
- 并行標(biāo)記清除
所謂并行,就是原來(lái)垃圾回收只是一個(gè)線程進(jìn)行。現(xiàn)在創(chuàng)建多個(gè)垃圾回收線程。并行的進(jìn)行標(biāo)記和清除。比如把需要標(biāo)記的對(duì)象平均分配到多個(gè)線程之后,當(dāng)標(biāo)記完成之后,多個(gè)線程進(jìn)行清除。
?
- 并發(fā)標(biāo)記清除
所謂并發(fā),就是應(yīng)用程序和垃圾回收可以同時(shí)執(zhí)行。在標(biāo)記清除算法中,在標(biāo)記對(duì)象和清除對(duì)象,以及壓縮對(duì)象的情況下是需要暫停應(yīng)用的。那么并行標(biāo)記清除壓縮算法則是在標(biāo)記清除壓縮算法的基礎(chǔ)上,把標(biāo)記清除壓縮算法分為以下幾個(gè)過(guò)程
初始標(biāo)記->并發(fā)標(biāo)記->重新標(biāo)記->并發(fā)清除->重置
?
以上幾種算法是垃圾回收的基本算法,jvm垃圾回收就是在以上幾種算法為基礎(chǔ)的,在以上幾種算法的基礎(chǔ)上,java垃圾回收器可以分為以下幾種:
- 串行收集器
用單線程處理所有垃圾回收工作,因?yàn)闊o(wú)需多線程交互,所以效率比較高。但是,也無(wú)法使用多處理器的優(yōu)勢(shì),所以此收集器適合單處理器機(jī)器
單線程收集器。在目前多核服務(wù)器端運(yùn)行的情況下,效率比較低。比較適合堆內(nèi)存小的情況下使用。
- 并行收集器
用多線程處理所有垃圾回收工作,利用多核處理器的優(yōu)勢(shì)。但是如果線程數(shù)量過(guò)多,導(dǎo)致線程之間頻繁調(diào)度,也會(huì)影響性能。一半并行收集的線程是處理器的個(gè)數(shù)。
“對(duì)吞吐量有高要求”,多CPU、對(duì)應(yīng)用響應(yīng)時(shí)間無(wú)要求的中、大型應(yīng)用。舉例:后臺(tái)處理、科學(xué)計(jì)算。
- 并發(fā)收集器
并發(fā)收集器主要減少年老代的暫停時(shí)間,他在應(yīng)用不停止的情況下使用獨(dú)立的垃圾回收線程,跟蹤可達(dá)對(duì)象。在每個(gè)年老代垃圾回收周期中,在收集初期并發(fā)收集器 會(huì)對(duì)整個(gè)應(yīng)用進(jìn)行簡(jiǎn)短的暫停(初始標(biāo)記的過(guò)程),在收集中還會(huì)再暫停一次。第二次暫停會(huì)比第一次稍長(zhǎng)(重新標(biāo)記的過(guò)程),在此過(guò)程中多個(gè)線程同時(shí)進(jìn)行垃圾回收工作。
并發(fā)收集器使用處理器換來(lái)短暫的停頓時(shí)間。在一個(gè)N個(gè)處理器的系統(tǒng)上,并發(fā)收集部分使用K/N個(gè)可用處理器進(jìn)行回收,一般情況下1<=K<=N/4。
在只有一個(gè)處理器的主機(jī)上使用并發(fā)收集器,設(shè)置為incremental mode模式也可獲得較短的停頓時(shí)間。
浮動(dòng)垃圾:由于在應(yīng)用運(yùn)行的同時(shí)進(jìn)行垃圾回收,所以有些垃圾可能在垃圾回收進(jìn)行完成時(shí)產(chǎn)生,這樣就造成了“Floating Garbage”,這些垃圾需要在下次垃圾回收周期時(shí)才能回收掉。所以,并發(fā)收集器一般需要20%的預(yù)留空間用于這些浮動(dòng)垃圾。
Concurrent Mode Failure:并發(fā)收集器在應(yīng)用運(yùn)行時(shí)進(jìn)行收集,所以需要保證堆在垃圾回收的這段時(shí)間有足夠的空間供程序使用,否則,垃圾回收還未完成,堆空間先滿(mǎn)了。這種情況下將會(huì)發(fā)生“并發(fā)模式失敗”,此時(shí)整個(gè)應(yīng)用將會(huì)暫停,進(jìn)行垃圾回收。
并發(fā)收集器,在垃圾回收的時(shí)候采用并發(fā)標(biāo)記清除算法的收集器
對(duì)響應(yīng)時(shí)間要求高的,多CPU,大型應(yīng)用。比如頁(yè)面請(qǐng)求/web服務(wù)器。前端業(yè)務(wù)系統(tǒng)用的比較多。
?
串行處理器:
--適用情況:數(shù)據(jù)量比較小(100M左右);單處理器下并且對(duì)響應(yīng)時(shí)間無(wú)要求的應(yīng)用。
--缺點(diǎn):只能用于小型應(yīng)用
并行處理器:
--適用情況:“對(duì)吞吐量有高要求”,多CPU、對(duì)應(yīng)用響應(yīng)時(shí)間無(wú)要求的中、大型應(yīng)用。舉例:后臺(tái)處理、科學(xué)計(jì)算。
--缺點(diǎn):垃圾收集過(guò)程中應(yīng)用響應(yīng)時(shí)間可能加長(zhǎng)
并發(fā)處理器:
--適用情況:“對(duì)響應(yīng)時(shí)間有高要求”,多CPU、對(duì)應(yīng)用響應(yīng)時(shí)間有較高要求的中、大型應(yīng)用。舉例:Web服務(wù)器/應(yīng)用服務(wù)器、電信交換、集成開(kāi)發(fā)環(huán)境。
JDK5.0適用的分代垃圾回收算法
?????? 分代的垃圾回收策略,是基于這樣一個(gè)事實(shí):不同的對(duì)象的生命周期是不一樣的。因此,不同生命周期的對(duì)象可以采取不同的收集方式,以便提高回收效率。
?????? 在Java程序運(yùn)行的過(guò)程中,會(huì)產(chǎn)生大量的對(duì)象,其中有些對(duì)象是與業(yè)務(wù)信息相關(guān),比如Http請(qǐng)求中的Session對(duì)象、線程、Socket連接,這類(lèi)對(duì)象跟業(yè)務(wù)直接掛鉤,因此生命周期比較長(zhǎng)。但是還有一些對(duì)象,主要是程序運(yùn)行過(guò)程中生成的臨時(shí)變量,這些對(duì)象生命周期會(huì)比較短,比如:String對(duì)象,由于其不變類(lèi)的特性,系統(tǒng)會(huì)產(chǎn)生大量的這些對(duì)象,有些對(duì)象甚至只用一次即可回收。
?????? 試想,在不進(jìn)行對(duì)象存活時(shí)間區(qū)分的情況下,每次垃圾回收都是對(duì)整個(gè)堆空間進(jìn)行回收,花費(fèi)時(shí)間相對(duì)會(huì)長(zhǎng),同時(shí),因?yàn)槊看位厥斩夹枰闅v所有存活對(duì)象,但實(shí)際上,對(duì)于生命周期長(zhǎng)的對(duì)象而言,這種遍歷是沒(méi)有效果的,因?yàn)榭赡苓M(jìn)行了很多次遍歷,但是他們依舊存在。因此,分代垃圾回收采用分治的思想,進(jìn)行代的劃分,把不同生命周期的對(duì)象放在不同代上,不同代上采用最適合它的垃圾回收方式進(jìn)行回收。
如何分代
如圖所示:
?????? 虛擬機(jī)中的共劃分為三個(gè)代:年輕代(Young Generation)、年老點(diǎn)(Old Generation)和持久代(Permanent Generation)。其中持久代主要存放的是Java類(lèi)的類(lèi)信息,與垃圾收集要收集的Java對(duì)象關(guān)系不大。年輕代和年老代的劃分是對(duì)垃圾收集影響比較大的。
年輕代:
????? 所有新生成的對(duì)象首先都是放在年輕代的。年輕代的目標(biāo)就是盡可能快速的收集掉那些生命周期短的對(duì)象。年輕代分三個(gè)區(qū)。一個(gè)Eden區(qū),兩個(gè)Survivor區(qū)(一般而言)。大部分對(duì)象在Eden區(qū)中生成。當(dāng)Eden區(qū)滿(mǎn)時(shí),還存活的對(duì)象將被復(fù)制到Survivor區(qū)(兩個(gè)中的一個(gè)),當(dāng)這個(gè)Survivor區(qū)滿(mǎn)時(shí),此區(qū)的存活對(duì)象將被復(fù)制到另外一個(gè)Survivor區(qū),當(dāng)這個(gè)Survivor去也滿(mǎn)了的時(shí)候,從第一個(gè)Survivor區(qū)復(fù)制過(guò)來(lái)的并且此時(shí)還存活的對(duì)象,將被復(fù)制“年老區(qū)(Tenured)”。需要注意,Survivor的兩個(gè)區(qū)是對(duì)稱(chēng)的,沒(méi)先后關(guān)系,所以同一個(gè)區(qū)中可能同時(shí)存在從Eden復(fù)制過(guò)來(lái) 對(duì)象,和從前一個(gè)Survivor復(fù)制過(guò)來(lái)的對(duì)象,而復(fù)制到年老區(qū)的只有從第一個(gè)Survivor去過(guò)來(lái)的對(duì)象。而且,Survivor區(qū)總有一個(gè)是空的。同時(shí),根據(jù)程序需要,Survivor區(qū)是可以配置為多個(gè)的(多于兩個(gè)),這樣可以增加對(duì)象在年輕代中的存在時(shí)間,減少被放到年老代的可能。
年老代:
????? 在年輕代中經(jīng)歷了N次垃圾回收后仍然存活的對(duì)象,就會(huì)被放到年老代中。因此,可以認(rèn)為年老代中存放的都是一些生命周期較長(zhǎng)的對(duì)象。
持久代:
????? 用于存放靜態(tài)文件,如今Java類(lèi)、方法等。持久代對(duì)垃圾回收沒(méi)有顯著影響,但是有些應(yīng)用可能動(dòng)態(tài)生成或者調(diào)用一些class,例如Hibernate等,在這種時(shí)候需要設(shè)置一個(gè)比較大的持久代空間來(lái)存放這些運(yùn)行過(guò)程中新增的類(lèi)。持久代大小通過(guò)-XX:MaxPermSize=<N>進(jìn)行設(shè)置。
什么情況下觸發(fā)垃圾回收
由于對(duì)象進(jìn)行了分代處理,因此垃圾回收區(qū)域、時(shí)間也不一樣。GC有兩種類(lèi)型:Scavenge GC和Full GC。
?
(1)新生代上的GC實(shí)現(xiàn) ? Serial:單線程的收集器,只使用一個(gè)線程進(jìn)行收集,并且收集時(shí)會(huì)暫停其他所有 工作線程(Stop the world)。它是Client模式下的默認(rèn)新生代收集器。 ? ParNew:Serial收集器的多線程版本。在單CPU甚至兩個(gè)CPU的環(huán)境下,由于線程 交互的開(kāi)銷(xiāo),無(wú)法保證性能超越Serial收集器。 ? Parallel Scavenge:也是多線程收集器,與ParNew的區(qū)別是,它是吞吐量優(yōu)先 收集器。吞吐量=運(yùn)行用戶(hù)代碼時(shí)間/(運(yùn)行用戶(hù)代碼+垃圾收集時(shí)間)。另一點(diǎn)區(qū)別 是配置-XX:+UseAdaptiveSizePolicy后,虛擬機(jī)會(huì)自動(dòng)調(diào)整Eden/Survivor等參數(shù)來(lái) 提供用戶(hù)所需的吞吐量。我們需要配置的就是內(nèi)存大小-Xmx和吞吐量GCTimeRatio。 ? (2)老年代上的GC實(shí)現(xiàn) ? Serial Old:Serial收集器的老年代版本。 ? Parallel Old:Parallel Scavenge的老年代版本。此前,如果新生代采用PS GC的話, 老年代只有Serial Old能與之配合。現(xiàn)在有了Parallel Old與之配合,可以在注重吞吐量 及CPU資源敏感的場(chǎng)合使用了。 ? CMS:采用的是標(biāo)記-清除而非標(biāo)記-整理,是一款并發(fā)低停頓的收集器。但是由于 采用標(biāo)記-清除,內(nèi)存碎片問(wèn)題不可避免。可以使用-XX:CMSFullGCsBeforeCompaction 設(shè)置執(zhí)行幾次CMS回收后,跟著來(lái)一次內(nèi)存碎片整理。?
GC類(lèi)型?
GC有兩種類(lèi)型:Scavenge GC和Full GC。?
1. Scavenge GC?
一般情況下,當(dāng)新對(duì)象生成,并且在Eden申請(qǐng)空間失敗時(shí),就好觸發(fā)Scavenge GC,堆Eden區(qū)域進(jìn)行GC,清除非存活對(duì)象,并且把尚且存活的對(duì)象移動(dòng)到Survivor區(qū)。然后整理Survivor的兩個(gè)區(qū)。?
2. Full GC?
對(duì)整個(gè)堆進(jìn)行整理,包括Young、Tenured和Perm。Full GC比Scavenge GC要慢,因此應(yīng)該盡可能減少Full GC。有如下原因可能導(dǎo)致Full GC:?
* Tenured被寫(xiě)滿(mǎn)?
* Perm域被寫(xiě)滿(mǎn)?
* System.gc()被顯示調(diào)用?
* 上一次GC之后Heap的各域分配策略動(dòng)態(tài)變化?
?
?
?
?
?
?
?
http://m.blog.csdn.net/blog/zhao9tian/39121819 from:http://blog.csdn.net/xiaomin1991222/article/details/50981410
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專(zhuān)家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的JVM垃圾回收算法 总结及汇总的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Java基础:JVM垃圾回收算法
- 下一篇: 图解JVM垃圾回收算法