天天看點

JVM學習之路(八)——垃圾回收算法

Java語言與C語言最大的差別就是記憶體自動回收,那麼JVM是怎麼控制記憶體回收的,這裡将介紹JVM垃圾回收的幾種算法,進而了解JVM記憶體回收的基本原理。

八、垃圾回收算法

(一)、stop the world

stop the world會在執行某一個垃圾回收算法的時候産生。JVM為了執行垃圾回收,會暫停java應用程式的執行,等垃圾回收完成後,再繼續運作。使用JMeter測試過java程式的同學,可能會發現在測試過程中,java程式有不規則的停頓現象,其實這就是“stop the world”,停頓的時候JVM是在做垃圾回收。是以盡可能減少stop the world的時間,就是優化JVM的主要目标。

(二)、引用計數法

原理:對一個對象被引用的次數進行計數,當增加一個引用時計數就加1,減少一個引用時計數就減1。當對象引用減少為0時,對象的記憶體空間将被回收掉。

特點:算法原理非常簡單,是最原始的回收算法。

缺點:

①頻繁的計數會影響性能

②它無法處理循環引用的問題。例如Father對象中引用了Son對象,Son對象中又引用了Father對象,這種情況下,對象将永遠無法被回收。正是由于以上2個缺點,java中并沒有使用這種算法。

(三)、标記清除

原理:

①标記:周遊所有的GC Roots,并将從GC Roots可達的對象設定為存活對象。注意:必須從GC Roots開始。

②清除:周遊堆中的所有對象(因為所有對象都存在于java堆中),将沒有被标記為可達的對象清除。

特點:标記清除算法執行過程中,會産生“stop the world”,讓java程式暫停等待,以保證在标記清除的過程中,不會有新的對象産生。為什麼必須暫停java程式呢?是這樣的,如果在标記過程完成後,又新産生了一個對象,而該對象已經錯過了标記期,那麼在接下來的清除流程中,這個新産生的對象因為未被标記,是以将被視為不可達對象而被清除,這樣程式就會出錯,是以标記清除算法在執行時,java程式将被暫停,産生“stop the world”。

缺點:

1、大量的記憶體周遊,執行性能較低,這也會導緻“stop the world”時間較長,java程式吞吐量降低。

2、在對象被清除之後,被清除的對象留下記憶體的空缺位置,造成記憶體不連續,空間浪費。

(四)、标記壓縮

原理:在标記清除算法的基礎上,增加了壓縮過程。

步驟:3個步驟:①标記、②清除、③壓縮。

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

特點:标記壓縮算法也會産生“stop the world”,不能和java程式并發執行。在壓縮過程中一些對象記憶體位址會發生改變,java程式隻能等待壓縮完成後才能繼續。

(五)、複制算法

原理:就是把記憶體一分為二,但隻使用其中一份,在垃圾回收時,将正在使用的那份記憶體中存活的對象複制到另一份空白的記憶體中,最後将正在使用的記憶體空間的對象清除,完成垃圾回收。

在新生代使用複制算法回收垃圾的過程:在GC開始的時候,對象隻會存在于Eden區和名為“From”的Survivor區,Survivor區“To”是空的。緊接着進行GC,Eden區中所有存活的對象都會被複制到“To”,而在“From”區中,仍存活的對象會根據他們的年齡值來決定去向。年齡達到一定值(年齡門檻值,可以通過-XX:MaxTenuringThreshold來設定)的對象會被移動到年老代中,沒有達到門檻值的對象會被複制到“To”區域。經過這次GC後,Eden區和From區已經被清空。這個時候,“From”和“To”會交換他們的角色,也就是新的“To”就是上次GC前的“From”,新的“From”就是上次GC前的“To”。不管怎樣,都會保證名為To的Survivor區域是空的。Minor GC會一直重複這樣的過程,直到“To”區被填滿,“To”區被填滿之後,會将所有對象移動到年老代中。

步驟:①标記、②複制、③清除

優點:複制算法相對标記壓縮算法來說更簡潔高效。

缺點:①不适合用于存活對象多的情況,因為那樣需要複制的對象很多,複制性能較差,是以複制算法往往用于記憶體空間中新生代的垃圾回收,因為新生代中存活對象較少,複制成本較低。②另外一個缺點是記憶體空間占用成本高,因為它基于兩份記憶體空間做對象複制,在非垃圾回收的周期内隻用到了一份記憶體空間,記憶體使用率較低。

這就是常見的垃圾回收算法,這些算法各有各的優缺點,但在JVM中并不是單純的使用特定的算法,而是使用的一種叫垃圾回收器的東西,垃圾回收器可以看做一系列垃圾回收算法的不同組合,在不同的場景使用合适的垃圾回收器,才能起到事半功倍的效果。

繼續閱讀