摘要:它的基本原理是,在每個(gè)對象中保存該對象的引用計(jì)數(shù),當(dāng)引用發(fā)生增減時(shí)對計(jì)數(shù)進(jìn)行更新。實(shí)現(xiàn)容易是引用計(jì)數(shù)算法最大的優(yōu)點(diǎn)。引用計(jì)數(shù)最大的缺點(diǎn),就是無法釋放循環(huán)引用的對象。為了避免這種情況的發(fā)生,對引用計(jì)數(shù)的操作必須采用獨(dú)占的方式來進(jìn)行。
jvm系列
垃圾回收基礎(chǔ)
JVM的編譯策略
GC的三大基礎(chǔ)算法
GC的三大高級算法
GC策略的評價(jià)指標(biāo)
JVM信息查看
GC通用日志解讀
jvm的card table數(shù)據(jù)結(jié)構(gòu)
Java類初始化順序
Java對象結(jié)構(gòu)及大小計(jì)算
Java的類加載機(jī)制
Java對象分配簡要流程
年老代過大有什么影響
Survivor空間溢出實(shí)例
關(guān)于Object=null
Java線程與Xss
基本術(shù)語 1. 垃圾(Garbage)就是需要回收的對象。
作為編寫程序的人,是可以做出“這個(gè)對象已經(jīng)不再需要了”這樣的判斷,但計(jì)算機(jī)是做不到的。因此,如果程序(通過某個(gè)變量等等)可能會直接或間接地引用一個(gè)對象,那么這個(gè)對象就被視為“存活”;與之相反,已經(jīng)引用不到的對象被視為“死亡”。將這些“死亡”對象找出來,然后作為垃圾進(jìn)行回收,這就是GC的本質(zhì)。
2、根(Root)就是判斷對象是否可被引用的起始點(diǎn)。
至于哪里才是根,不同的語言和編譯器都有不同的規(guī)定,但基本上是將變量和運(yùn)行棧空間作為根。好了,用上面這兩個(gè)術(shù)語,我們來講一講主要的GC算法。
三大基礎(chǔ)GC算法 1、標(biāo)記清除法/標(biāo)記壓縮法標(biāo)記清除(Mark and Sweep)是最早開發(fā)出的GC算法(1960年)。它的原理非常簡單,首先從根開始將可能被引用的對象用遞歸的方式進(jìn)行標(biāo)記,然后將沒有標(biāo)記到的對象作為垃圾進(jìn)行回收。
圖1顯示了標(biāo)記清除算法的大致原理。圖1中的(1)部分顯示了隨著程序的運(yùn)行而分配出一些對象的狀態(tài),一個(gè)對象可以對其他的對象進(jìn)行引用。圖中(2)部分中,GC開始執(zhí)行,從根開始對可能被引用的對象打上“標(biāo)記”。大多數(shù)情況下,這種標(biāo)記是通過對象內(nèi)部的標(biāo)志(Flag)來實(shí)現(xiàn)的。于是,被標(biāo)記的對象我們把它們涂黑。圖中(3)部分中,被標(biāo)記的對象所能夠引用的對象也被打上標(biāo)記。重復(fù)這一步驟的話,就可以將從根開始可能被間接引用到的對象全部打上標(biāo)記。到此為止的操作,稱為標(biāo)記階段(Mark phase)。
標(biāo)記階段完成時(shí),被標(biāo)記的對象就被視為“存活”對象。圖1中的(4)部分中,將全部對象按順序掃描一遍,將沒有被標(biāo)記的對象進(jìn)行回收。這一操作被稱為清除階段(Sweep phase)。
在掃描的同時(shí),還需要將存活對象的標(biāo)記清除掉,以便為下一次GC操作做好準(zhǔn)備。標(biāo)記清除算法的處理時(shí)間,是和存活對象數(shù)與對象總數(shù)的總和相關(guān)的。
作為標(biāo)記清除的變形,還有一種叫做標(biāo)記壓縮(Mark and Compact)的算法,它不是將被標(biāo)記的對象清除,而是將它們不斷壓縮。
2、復(fù)制收集算法標(biāo)記清除算法有一個(gè)缺點(diǎn),就是在分配了大量對象,并且其中只有一小部分存活的情況下,所消耗的時(shí)間會大大超過必要的值,這是因?yàn)樵谇宄A段還需要對大量死亡對象進(jìn)行掃描。復(fù)制收集(Copy and Collection)則試圖克服這一缺點(diǎn)。在這種算法中,會將從根開始被引用的對象復(fù)制到另外的空間中,然后,再將復(fù)制的對象所能夠引用的對象用遞歸的方式不斷復(fù)制下去。
圖2的(1)部分是GC開始前的內(nèi)存狀態(tài),這和圖1的(1)部分是一樣的。圖2的(2)部分中,在舊對象所在的“舊空間”以外,再準(zhǔn)備出一塊“新空間”,并將可能從根被引用的對象復(fù)制到新空間中。圖中(3)部分中,從已經(jīng)復(fù)制的對象開始,再將可以被引用的對象像一串糖葫蘆一樣復(fù)制到新空間中。復(fù)制完成之后,“死亡”對象就被留在了舊空間中。圖中(4)部分中,將舊空間廢棄掉,就可以將死亡對象所占用的空間一口氣全部釋放出來,而沒有必要再次掃描每個(gè)對象。下次GC的時(shí)候,現(xiàn)在的新空間也就變成了將來的舊空間。
通過圖2我們可以發(fā)現(xiàn),復(fù)制收集方式中,只存在相當(dāng)于標(biāo)記清除方式中的標(biāo)記階段。由于清除階段中需要對現(xiàn)存的所有對象進(jìn)行掃描,在存在大量對象,且其中大部分都即將死亡的情況下,全部掃描一遍的開銷實(shí)在是不小。而在復(fù)制收集方式中,就不存在這樣的開銷。
但是,和標(biāo)記相比,將對象復(fù)制一份所需要的開銷則比較大,因此在“存活”對象比例較高的情況下,反而會比較不利。這種算法的另一個(gè)好處是它具有局部性(Lo-cality)。在復(fù)制收集過程中,會按照對象被引用的順序?qū)ο髲?fù)制到新空間中。于是,關(guān)系較近的對象被放在距離較近的內(nèi)存空間中的可能性會提高,這被稱為局部性。局部性高的情況下,內(nèi)存緩存會更容易有效運(yùn)作,程序的運(yùn)行性能也能夠得到提高。
3、引用計(jì)數(shù)法引用計(jì)數(shù)(Reference Count)方式是GC算法中最簡單也最容易實(shí)現(xiàn)的一種,它和標(biāo)記清除方式差不多是在同一時(shí)間發(fā)明出來的。它的基本原理是,在每個(gè)對象中保存該對象的引用計(jì)數(shù),當(dāng)引用發(fā)生增減時(shí)對計(jì)數(shù)進(jìn)行更新。引用計(jì)數(shù)的增減,一般發(fā)生在變量賦值、對象內(nèi)容更新、函數(shù)結(jié)束(局部變量不再被引用)等時(shí)間點(diǎn)。當(dāng)一個(gè)對象的引用計(jì)數(shù)變?yōu)?時(shí),則說明它將來不會再被引用,因此可以釋放相應(yīng)的內(nèi)存空間。
圖3的(1)部分中,所有對象中都保存著自己被多少個(gè)其他對象進(jìn)行引用的數(shù)量(引用計(jì)數(shù)),圖中每個(gè)對象右上角的數(shù)字就是引用計(jì)數(shù)。圖中(2)部分中,當(dāng)對象引用發(fā)生變化時(shí),引用計(jì)數(shù)也跟著變化。在這里,由對象B到對象D的引用失效了,于是對象D的引用計(jì)數(shù)變?yōu)?。由于對象D的引用計(jì)數(shù)為0,因此由對象D到對象C和E的引用數(shù)也分別相應(yīng)減少。結(jié)果,對象E的引用計(jì)數(shù)也變?yōu)?,于是對象E也被釋放掉了。圖3的(3)部分中,引用計(jì)數(shù)變?yōu)?的對象被釋放,“存活”對象則保留了下來。大家應(yīng)該注意到,在整個(gè)GC處理過程中,并不需要對所有對象進(jìn)行掃描。
實(shí)現(xiàn)容易是引用計(jì)數(shù)算法最大的優(yōu)點(diǎn)。標(biāo)記清除和復(fù)制收集這些GC機(jī)制在實(shí)現(xiàn)上都有一定難度;而引用計(jì)數(shù)方式的話,凡是有些年頭的C++程序員(包括我在內(nèi)),應(yīng)該都曾經(jīng)實(shí)現(xiàn)過類似的機(jī)制,可以說這種算法是相當(dāng)具有普遍性的。除此之外,當(dāng)對象不再被引用的瞬間就會被釋放,這也是一個(gè)優(yōu)點(diǎn)。其他的GC機(jī)制中,要預(yù)測一個(gè)對象何時(shí)會被釋放是很困難的,而在引用計(jì)數(shù)方式中則是立即被釋放的。而且,由于釋放操作是針對每個(gè)對象個(gè)別執(zhí)行的,因此和其他算法相比,由GC而產(chǎn)生的中斷時(shí)間(Pause time)就比較短,這也是一個(gè)優(yōu)點(diǎn)。
引用計(jì)數(shù)方式的缺點(diǎn)另一方面,這種方式也有缺點(diǎn)。引用計(jì)數(shù)最大的缺點(diǎn),就是無法釋放循環(huán)引用的對象。
圖4中,A、B、C三個(gè)對象沒有被其他對象引用,而是互相之間循環(huán)引用,因此它們的引用計(jì)數(shù)永遠(yuǎn)不會為0,結(jié)果這些對象就永遠(yuǎn)不會被釋放。引用計(jì)數(shù)的第二個(gè)缺點(diǎn),就是必須在引用發(fā)生增減時(shí)對引用計(jì)數(shù)做出正確的增減,而如果漏掉了某個(gè)增減的話,就會引發(fā)很難找到原因的內(nèi)存錯(cuò)誤。引用數(shù)忘了增加的話,會對不恰當(dāng)?shù)膶ο筮M(jìn)行釋放;而引用數(shù)忘了減少的話,對象會一直殘留在內(nèi)存中,從而導(dǎo)致內(nèi)存泄漏。如果語言編譯器本身對引用計(jì)數(shù)進(jìn)行管理的話還好,否則,如果是手動(dòng)管理引用計(jì)數(shù)的話,那將成為孕育bug的溫床。
最后一個(gè)缺點(diǎn)就是,引用計(jì)數(shù)管理并不適合并行處理。如果多個(gè)線程同時(shí)對引用計(jì)數(shù)進(jìn)行增減的話,引用計(jì)數(shù)的值就可能會產(chǎn)生不一致的問題(結(jié)果則會導(dǎo)致內(nèi)存錯(cuò)誤)。為了避免這種情況的發(fā)生,對引用計(jì)數(shù)的操作必須采用獨(dú)占的方式來進(jìn)行。如果引用操作頻繁發(fā)生,每次都要使用加鎖等并發(fā)控制機(jī)制的話,其開銷也是不可小覷的。綜上所述,引用計(jì)數(shù)方式的原理和實(shí)現(xiàn)雖然簡單,但缺點(diǎn)也很多,因此最近基本上不再使用了?,F(xiàn)在,依然采用引用計(jì)數(shù)方式的語言主要有Perl和Python,但它們?yōu)榱吮苊庋h(huán)引用的問題,都配合使用了其他的GC機(jī)制。這些語言中,GC基本上是通過引用計(jì)數(shù)方式來進(jìn)行的,但偶爾也會用其他的算法來執(zhí)行GC,這樣就可以將引用計(jì)數(shù)方式無法回收的那些對象處理掉。
引用代碼的未來
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/65639.html
摘要:現(xiàn)在,通過對這三種方式進(jìn)行融合,出現(xiàn)了一些更加高級的方式。這樣一來,需要掃描的對象數(shù)量就會大幅減少。像這樣以全部區(qū)域?yàn)閷ο蟮牟僮鞅环Q為完全回收或者大回收。在一般的算法中,作出這樣的保證是不可能的,因?yàn)楫a(chǎn)生的中斷時(shí)間與對象的數(shù)量和狀態(tài)有關(guān)。 jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級算法 GC策略的評價(jià)指標(biāo) JVM信息查看 GC通用日志解讀 jvm的...
摘要:系統(tǒng)總運(yùn)行時(shí)間應(yīng)用程序耗時(shí)耗時(shí)。一般而言,頻率越低越好,通常增大堆空間可以有效降低垃圾回收發(fā)生的頻率,但是會增加回收時(shí)產(chǎn)生的停頓時(shí)間。反應(yīng)時(shí)間當(dāng)一個(gè)對象成為垃圾后,多長時(shí)間內(nèi),它所占用的內(nèi)存空間會被釋放掉。 jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級算法 GC策略的評價(jià)指標(biāo) JVM信息查看 GC通用日志解讀 jvm的card table數(shù)據(jù)結(jié)構(gòu) J...
摘要:在一般應(yīng)用中,不會逃逸的局部對象所占的比例很大,如果能使用棧上分配,那大量的對象就會隨著方法的結(jié)束而自動(dòng)銷毀了,垃圾收集系統(tǒng)的壓力將會小很多。相關(guān)參數(shù)設(shè)置大對象直接進(jìn)入年老代的閾值,當(dāng)對象大小超過這個(gè)值時(shí),將直接在年老代分配。 jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級算法 GC策略的評價(jià)指標(biāo) JVM信息查看 GC通用日志解讀 jvm的card t...
摘要:系列垃圾回收基礎(chǔ)的編譯策略的三大基礎(chǔ)算法的三大高級算法策略的評價(jià)指標(biāo)信息查看通用日志解讀的數(shù)據(jù)結(jié)構(gòu)類初始化順序?qū)ο蠼Y(jié)構(gòu)及大小計(jì)算的類加載機(jī)制對象分配簡要流程年老代過大有什么影響空間溢出實(shí)例關(guān)于線程與序本文主要講述如何查看應(yīng)用的信息。 jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級算法 GC策略的評價(jià)指標(biāo) JVM信息查看 GC通用日志解讀 jvm的car...
摘要:系列垃圾回收基礎(chǔ)的編譯策略的三大基礎(chǔ)算法的三大高級算法策略的評價(jià)指標(biāo)信息查看通用日志解讀的數(shù)據(jù)結(jié)構(gòu)類初始化順序?qū)ο蠼Y(jié)構(gòu)及大小計(jì)算的類加載機(jī)制對象分配簡要流程年老代過大有什么影響空間溢出實(shí)例關(guān)于線程與序本文主要講述日志的解讀。 jvm系列 垃圾回收基礎(chǔ) JVM的編譯策略 GC的三大基礎(chǔ)算法 GC的三大高級算法 GC策略的評價(jià)指標(biāo) JVM信息查看 GC通用日志解讀 jvm的card ta...
閱讀 749·2021-10-09 09:44
閱讀 2029·2021-09-22 15:54
閱讀 5066·2021-09-22 10:55
閱讀 1448·2019-08-29 18:41
閱讀 784·2019-08-29 11:24
閱讀 2110·2019-08-28 18:20
閱讀 1035·2019-08-26 11:51
閱讀 3055·2019-08-26 11:00