我們都知道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。
上圖表示3個Teacher的參考指向堆中的Teacher對象,那麼Teacher物件的參考計數就是3 ,以此類推Student物件的引用計數就是2。
#上圖表示Teacher物件的參考減少為2, Student物件的引用減少為0(減少的原因是該引用指向了null,例如teacher3=null),按照引用計數演算法,Student物件的記憶體空間將被回收掉。
引用計數演算法原理非常簡單,是最原始的回收演算法,但是java中沒有使用這種演算法,原因有2。1是頻繁的計數影響效能,2是它無法處理循環引用的問題。
例如Teacher物件中引用了Student對象,Student物件中又引用了Teacher對象,這種情況下,物件將永遠無法被回收。
標記清除
標記清除演算法,它是許多垃圾回收演算法的基礎,簡單來說有兩個步驟:標記、清除。
標記:遍歷所有的GC Roots,並將從GC Roots可達的物件設定為存活物件;
清除:遍歷堆中的所有對象,將沒有被標記可達的對象清除;
#注意上圖灰色的對象,因為從GC Root遍歷不到它們(儘管它們本身有引用關係,但從GC Root無法遍歷到它們),因此它們沒有被標記為存活對象,在清除過程中將會被回收。
這裡需要注意的是標記清除演算法執行過程中,會產生“stop the world”,讓java程式暫停等待以保證在標記清除的過程中,不會有新的對象產生。為什麼必須暫停java程式呢?舉個例子,如果在標記過程完成後,又新產生了一個對象,而該對像已經錯過了標記期,那麼在接下來的清除流程中,這個新產生的對象因為未被標記,所以將被視為不可達物件而被清除,這樣程式就會出錯,因此標記清除演算法在執行時,java程式將被暫停,產生「stop the world」。
接下來我們總結標記清除演算法:
1、因為涉及大量的記憶體遍歷工作,所以執行效能較低,這也會導致「stop the world」時間較長,java程式吞吐量降低;
#2、我們注意到物件被清除之後,被清除的物件留下記憶體的空缺位置,造成記憶體不連續,空間浪費。
接下來我們來看其他演算法能不能改善這些問題?
標記壓縮
標記壓縮演算法你可能已經想到了,它就是在標記清除演算法的基礎上,增加了壓縮過程。
在進行完標記清除之後,對記憶體空間進行壓縮,節省記憶體空間,解決了標記清除演算法內存不連續的問題。
注意標記壓縮演算法也會產生“stop the world”,不能和java程式並發執行。在壓縮過程中一些物件記憶體位址會改變,java程式只能等待壓縮完成後才能繼續。
複製演算法
複製演算法簡單來說就是將記憶體一分為二,但只使用其中一份,在垃圾回收時,將正在使用的那份記憶體中存活的物件複製到另一份空白的記憶體中,最後將正在使用的記憶體空間的物件清除,完成垃圾回收。
複製演算法相對標記壓縮演算法來說更簡潔高效,但它的缺點也顯而易見,它不適合用於存活物件多的情況,因為那樣需要複製的物件很多,複製效能較差,所以複製演算法往往用於記憶體空間中新生代的垃圾回收,因為新生代中存活對象較少,複製成本較低。它另一個缺點是記憶體空間佔用成本高,因為它基於兩份記憶體空間做物件複製,在非垃圾回收的週期內只用到了一份記憶體空間,記憶體利用率較低。
小結
以上我們介紹了常見的垃圾回收演算法,這些演算法各有各的優缺點,但在JVM中並不是單純的使用特定的演算法,而是使用的一種叫做垃圾回收器的東西,垃圾回收器可以看做一系列演算法的不同組合,在不同的場景使用合適的垃圾回收器,才能起到事半功倍的效果。我們下一篇將介紹垃圾回收器。
參考資料:#《實戰Java虛擬機》 葛一鳴《深入理解Java虛擬機(第2版)》 週志明
################################## ##########
以上是jvm垃圾回收演算法的詳細內容。更多資訊請關注PHP中文網其他相關文章!