GC的四種清理演算法
1.標記-清除:
這是垃圾收集演算法中最基礎的,根據名字就可以知道,它的思想就是標記哪些要被回收的物件,然後統一回收。這種方法很簡單,但是會有兩個主要問題:
- 效率不高,標記和清除的效率都很低;
- 會產生大量不連續的記憶體碎片,導致以後程式在分配較大的物件時,由於沒有充足的連續記憶體而提前觸發一次
GC
動作。
2.複製演算法:
為了解決效率問題,複製演算法將可用記憶體按容量劃分為相等的兩部分,然後每次只使用其中的一塊,當一塊記憶體用完時,就將還存活的物件複製到第二塊記憶體上,然後一次性清楚完第一塊記憶體,再將第二塊上的物件複製到第一塊。但是這種方式,記憶體的代價太高,每次基本上都要浪費一般的記憶體。
於是將該演算法進行了改進,記憶體區域不再是按照1:1去劃分,而是將記憶體劃分為8:1:1三部分,較大那份記憶體交Eden
區,其餘是兩塊較小的記憶體區叫Survior
區。每次都會優先使用Eden
區,若Eden
區滿,就將物件複製到第二塊記憶體區上,然後清除Eden
區,如果此時存活的物件太多,以至於Survivor
不夠時,會將這些物件通過分配擔保機制複製到老年代中。(java堆又分為新生代和老年代)
3.標記-整理
該演算法主要是為了解決標記-清除,產生大量記憶體碎片的問題;當物件存活率較高時,也解決了複製演算法的效率問題。它的不同之處就是在清除物件的時候現將可回收物件移動到一端,然後清除掉端邊界以外的物件,這樣就不會產生記憶體碎片了。
4.分代收集
現在的虛擬機器垃圾收集大多采用這種方式,它根據物件的生存週期,將堆分為新生代和老年代。在新生代中,由於物件生存期短,每次回收都會有大量物件死去,那麼這時就採用複製演算法。老年代裡的物件存活率較高,沒有額外的空間進行分配擔保,所以可以使用標記-整理 或者 標記-清除。
記憶體清除演算法
1.標記-清除:
標記 GC roots
可達的物件,清理掉沒有被標記的物件。
做法:當堆中的有效記憶體空間被耗盡的時候,就會停止整個程式,然後進行兩項工作,第一項是標記,第二項是清除。
- 標記:遍歷所有的
GC Roots
,然後將GC Roots
可達的物件標記為存活的物件。 - 清除:清除的過程將遍歷對中所有的物件,將沒有標記的物件全部清除掉。
當程式執行期間,若可以使用的記憶體被耗盡的時候,GC
執行緒就會被觸發並將程式暫停,隨後將依舊存活的物件標記一遍,最終再將堆中所有沒被標記的物件全部清除掉,接下來便讓程式恢復執行。
標記的時候為什麼有停止程式執行呢?
假設我們剛標記完圖中最右邊的那個物件,暫且記為A,結果此時在程式當中又new
了一個新物件B,且A物件可以到達B物件。但是由於此時A物件已經標記結束,B物件此時的標記位依然是0,因為它錯過了標記階段。因此當接下來輪到清除階段的時候,新物件B將會被苦逼的清除掉。如此一來,不難想象結果,GC
執行緒將會導致程式無法正常工作。上面的結果當然令人無法接受,我們剛new
了一個物件,結果經過一次GC
,忽然變成null
了,這還怎麼玩?
缺點:
- 效率較低(遞迴,遍歷整個堆的物件)而且在進行
GC
的時候,需要停止應用程式,這會導致使用者體驗非常差勁。 - 清理出來的記憶體空間不是連續的(死亡物件都是隨機出現在記憶體的各個角落的)。再分配陣列物件的時候,尋找連續的記憶體空間不太好找。
2.複製演算法:
將記憶體分為兩塊
做法:當記憶體空間耗盡時,暫停程式執行,開啟複製演算法GC
執行緒。將活動區間(記憶體)的存活物件複製到空閒的那一塊記憶體區域,並且嚴格的按照記憶體地址依次排列,與此同時GC
執行緒將更新存活物件的記憶體引用地址指向新的記憶體地址。 將標記為死亡物件一次清除掉。之後(活動)的那一塊記憶體區域變為空閒,空閒的變為忙。
缺點:
1. 浪費了一半記憶體。
2. 如果物件的存活率很高,假設為100%存活,那麼就需要將所有物件都複製一遍,並且將所有引用地址複製一遍。複製這一工作所話費的時間,在物件存活率達到一定程度時,(複製所用時間)將會變的不可忽視。
總結:要想使用複製演算法,最起碼物件的存活率要非常低才行,而且最重要的是,我們必須要克服50%
的記憶體浪費。
3.標記-整理演算法:
做法:
- 和標記-清除演算法一樣,標記出存活的物件。
- 按照記憶體地址依次排列,而未被標記的記憶體會被清理掉。
不難看出,標記-整理演算法不僅可以彌補 標記-清除 演算法中記憶體區要分散的缺點,也消除了複製演算法中記憶體減半的高額代價。(但是從效率上講,標記-整理演算法要低於複製演算法)
演算法總結:
- 都是基於根搜尋演算法(
GC Roots
)的來判斷一個物件是否應該被回收 - 在
GC
執行緒開啟時,或者說GC
過程開始時,它們都要暫停服務。 - 效率:
- 複製演算法 > 標記/整理演算法 > 標記/清除演算法(此處的效率只是簡單的對比時間複雜度,實際情況不一定如此)。
- 記憶體整齊度:複製演算法 = 標記/整理演算法 > 標記/清除演算法。
- 記憶體利用率:標記/整理演算法 = 標記/清除演算法 > 複製演算法。
結束語
到此我們已經將三個演算法瞭解清楚了,可以看出,效率上來說,複製演算法是當之無愧的老大,但是卻浪費了太多記憶體,而為了儘量兼顧上面所提到的三個指標,標記/整理演算法相對來說更平滑一些,但效率上依然不盡如人意,它比複製演算法多了一個標記的階段,又比標記/清除多了一個整理記憶體的過程。
難道就沒有一種最優演算法嗎?
當然是沒有的,這個世界是公平的,任何東西都有兩面性,試想一下,你怎麼可能找到一個又漂亮又勤快又有錢又通情達理,性格又合適,家境也合適,身高長相等等等等都合適的女人?就算你找到了,至少有一點這個女人也肯定不滿足,那就是多半不會恰巧又愛上了與LZ相似的各位苦逼猿友們。你是不是想說你比LZ強太多了,那LZ只想對你說,高富帥是不會爬在電腦前看技術文章的,0.0。
但是古人就是給力,古人說了,找媳婦不一定要找最好的,而是要找最合適的,聽完這句話,瞬間感覺世界美好了許多。
演算法也是一樣的,沒有最好的演算法,只有最合適的演算法。
既然這三種演算法都各有缺陷,高人們自然不會容許這種情況發生。因此,高人們提出可以根據物件的不同特性,使用不同的演算法處理,類似於蘿蔔白菜各有所愛的原理。於是奇蹟發生了,高人們終於找到了GC
演算法中的神級演算法—–分代蒐集演算法。
4.!分代蒐集演算法:
本質 屬於前三種演算法的實際應用 新生代,老年代,永久代
新生代:朝生夕滅,存活時間短。eg:某一個方法的區域性變數,迴圈內的臨時變數等等。
老年代:生存時間長,但總會死亡。eg:快取物件,資料庫連線物件,單例物件等等。
永久代:幾乎一直不滅。eg:String池中的物件,載入過的類資訊。
java堆:新生代,老年代 方法區(永久代):
使用這樣的方式,我們只浪費了10%的記憶體,這個是可以接受的,因為我們換來了記憶體的整齊排列與GC
速度。第二點是,這個策略的前提是,每次存活的物件佔用的記憶體不能超過這10%的大小,一旦超過,多出的物件將無法複製。
為了解決上面的意外情況,也就是存活物件佔用的記憶體太大時的情況,高手們將JAVA堆分成兩部分來處理,上述三個區域則是第一部分,稱為新生代或者年輕代。而餘下的一部分,專門存放老不死物件的則稱為年老代。
JVM
在進行GC
時,並非每次都對上面三個區域一起回收,大部分回收的是新生代。因此GC
按照回收的區域又分為兩種:普通GC,全域性GC
普通GC
:只針對新生代區域的GC
全域性GC
:針對老年代的GC
,偶爾伴隨新生代的GC
以及對永久帶的GC
由於年老代與永久代相對來說GC
效果不好,而且二者的記憶體使用增長速度也慢,因此一般情況下,需要經過好幾次普通GC
,才會觸發一次全域性GC
。
相關文章
- JVM的四種GC演算法JVMGC演算法
- php常用的四種排序演算法PHP排序演算法
- 圖解Golang的GC演算法圖解GolangGC演算法
- PHP四種基本排序演算法示例PHP排序演算法
- JVM(六)——GC 演算法JVMGC演算法
- GC演算法介紹GC演算法
- 對四種限流演算法的思考和總結演算法
- 十種GC垃圾回收器GC
- PHP實現四種基本排序演算法PHP排序演算法
- PHP 四種基本排序演算法的程式碼實現PHP排序演算法
- 【JVM第八篇--垃圾回收】GC和GC演算法JVMGC演算法
- LRU演算法四種實現方式介紹演算法
- 垃圾回收演算法|GC標記-清除演算法演算法GC
- 美國商務部公佈四種抗量子的加密演算法加密演算法
- Java的四種引用Java
- Activity的四種launchMode
- 面試必備:四種經典限流演算法講解面試演算法
- 一種KV儲存的GC最佳化實踐GC
- OAuth 2.0 的四種方式OAuth
- CSS的四種引入方式CSS
- NVMe SSD的GC演算法與模擬原理解析GC演算法
- Java記憶體模型及GC演算法Java記憶體模型GC演算法
- Minor GC、Major GC以及Full GC的介紹及對比GC
- mongodb清理collection中大量資料的2種辦法MongoDB
- 【作業系統】磁碟的四種基本排程演算法(圖表說明)作業系統演算法
- 《垃圾回收的演算法與實現》第2章GC標記-清除演算法演算法GC
- jvm系列(三)GC演算法 垃圾收集器JVMGC演算法
- JVM 系列文章之 GC 演算法淺析JVMGC演算法
- 從歷代GC演算法角度刨析ZGCGC演算法
- java中Stream的四種建立Java
- Java 四種引用的解讀Java
- Spark的四種部署方式概括Spark
- PostgreSQL的四種程式間鎖SQL
- Java 建立類的四種方式Java
- TCP的四種定時器TCP定時器
- mysql啟動的四種方式MySql
- oracle關閉的四種模式Oracle模式
- Mysql的四種啟動方式MySql