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