深入理解JVM(四)——垃圾回收演算法

飄揚的紅領巾發表於2017-08-18

    我們都知道java語言與C語言最大的區別就是記憶體自動回收,那麼JVM是怎麼控制記憶體回收的,這篇文章將介紹JVM垃圾回收的幾種演算法,從而瞭解記憶體回收的基本原理。

stop the world

    在介紹垃圾回收演算法之前,我們需要先了解一個詞“stop the world”,stop the world會在執行某一個垃圾回收演算法的時候產生,JVM為了執行垃圾回收,會暫時java應用程式的執行,等垃圾回收完成後,再繼續執行。如果你使用JMeter測試過java程式,你可能會發現在測試過程中,java程式有不規則的停頓現象,其實這就是“stop the world”,停頓的時候JVM是在做垃圾回收。所以儘可能減少stop the world的時間,就是我們最佳化JVM的主要目標。接下來我們看一下目前有哪些常見垃圾回收的演算法。

引用計數法

引用計數法顧名思義,就是對一個物件被引用的次數進行計數,當增加一個引用計數就加1,減少一個引用計數就減1。

image

上圖表示3個Teacher的引用指向堆中的Teacher物件,那麼Teacher物件的引用計數就是3,以此類推Student物件的引用計數就是2。

image

 

上圖表示Teacher物件的引用減少為2,Student物件的引用減少為0(減少的原因是該引用指向了null,例如teacher3=null),按照引用計數演算法,Student物件的記憶體空間將被回收掉。

引用計數演算法原理非常簡單,是最原始的回收演算法,但是java中沒有使用這種演算法,原因有2。1是頻繁的計數影響效能,2是它無法處理迴圈引用的問題。

例如Teacher物件中引用了Student物件,Student物件中又引用了Teacher物件,這種情況下,物件將永遠無法被回收。

標記清除

標記清除演算法,它是很多垃圾回收演算法的基礎,簡單來說有兩個步驟:標記、清除。

標記:遍歷所有的GC Roots,並將從GC Roots可達的物件設定為存活物件;

清除:遍歷堆中的所有物件,將沒有被標記可達的物件清除;

image

注意上圖灰色的物件,因為從GC Root遍歷不到它們(儘管它們本身有引用關係,但從GC Root無法遍歷到它們),因此它們沒有被標記為存活物件,在清除過程中將會被回收。

這裡需要注意的是標記清除演算法執行過程中,會產生“stop the world”,讓java程式暫停等待以保證在標記清除的過程中,不會有新的物件產生。為什麼必須暫停java程式呢?舉個例子,如果在標記過程完成後,又新產生了一個物件,而該物件已經錯過了標記期,那麼在接下來的清除流程中,這個新產生的物件因為未被標記,所以將被視為不可達物件而被清除,這樣程式就會出錯,因此標記清除演算法在執行時,java程式將被暫停,產生“stop the world”。

接下來我們總結一下標記清除演算法:

1、因為涉及大量的記憶體遍歷工作,所以執行效能較低,這也會導致“stop the world”時間較長,java程式吞吐量降低;

2、我們注意到物件被清除之後,被清除的物件留下記憶體的空缺位置,造成記憶體不連續,空間浪費。

接下來我們看一下其他演算法能不能改善這些問題?

標記壓縮

標記壓縮演算法你可能已經想到了,它就是在標記清除演算法的基礎上,增加了壓縮過程。

image

在進行完標記清除之後,對記憶體空間進行壓縮,節省記憶體空間,解決了標記清除演算法記憶體不連續的問題。

注意標記壓縮演算法也會產生“stop the world”,不能和java程式併發執行。在壓縮過程中一些物件記憶體地址會發生改變,java程式只能等待壓縮完成後才能繼續。

複製演算法

    複製演算法簡單來說就是把記憶體一分為二,但只使用其中一份,在垃圾回收時,將正在使用的那份記憶體中存活的物件複製到另一份空白的記憶體中,最後將正在使用的記憶體空間的物件清除,完成垃圾回收。

image

image

 

 

image

image

    複製演算法相對標記壓縮演算法來說更簡潔高效,但它的缺點也顯而易見,它不適合用於存活物件多的情況,因為那樣需要複製的物件很多,複製效能較差,所以複製演算法往往用於記憶體空間中新生代的垃圾回收,因為新生代中存活物件較少,複製成本較低。它另外一個缺點是記憶體空間佔用成本高,因為它基於兩份記憶體空間做物件複製,在非垃圾回收的週期內只用到了一份記憶體空間,記憶體利用率較低。

小結

    以上我們介紹了常見的垃圾回收演算法,這些演算法各有各的優缺點,但在JVM中並不是單純的使用特定的演算法,而是使用的一種叫垃圾回收器的東西,垃圾回收器可以看做一系列演算法的不同組合,在不同的場景使用合適的垃圾回收器,才能起到事半功倍的效果。我們下一篇將介紹垃圾回收器。

 

參考資料:

《實戰Java虛擬機器》 葛一鳴

《深入理解Java虛擬機器(第2版)》 周志明

 

相關文章