JVM-05垃圾收集Garbage Collection(中)【垃圾收集算法】
文章目錄
- 思維導圖
- 標記清除算法(其他算法的基礎)
- 復制算法(新生代的GC)
- 標記整理/壓縮算法(老年代的GC)
- 標記-清除算法、復制算法、標記整理算法總結
- 分代收集算法(新生代的GC+老年代的GC)
思維導圖
JVM-04垃圾收集Garbage Collection(上)【垃圾對象的判定】探討了如何判定堆內存中的對象是否已經死亡,這里我們來繼續討論下JVM中常用的垃圾收集算法
標記清除算法(其他算法的基礎)
標記-清除算法是現代垃圾回收算法的思想基礎。標記-清除算法將垃圾回收分為兩個階段:標記階段和清除階段。一種可行的實現是,在標記階段,首先通過根節點,標記所有從根節點開始的可達對象。因此,未被標記的對象就是未被引用的垃圾對象;然后,在清除階段,清除所有未被標記的對象。
當堆中的有效內存空間(available memory)被耗盡的時候,就會停止整個程序(也被成為stop the world),然后進行兩項工作,第一項則是標記,第二項則是清除
標記:遍歷所有的GC Roots,并將從GC Roots可達的對象設置為存活對象;
清除:遍歷堆中的所有對象,將沒有被標記可達的對象清除;
也就是說,就是當程序運行期間,若可以使用的內存被耗盡的時候,GC線程就會被觸發并將程序暫停,隨后將依舊存活的對象標記一遍,最終再將堆中所有沒被標記的對象全部清除掉,接下來便讓程序恢復運行。
優缺點:
- 涉及大量的內存遍歷工作,所以執行性能較低,這也會導致“stop the world”時間較長,java程序吞吐量降低;
- 對象被清除之后,被清除的對象留下內存的空缺位置,造成內存不連續,空間浪費。
復制算法(新生代的GC)
將現有的內存空間分為兩快,每次只使用其中一塊,在垃圾回收時將正在使用的內存中的存活對象復制到未被使用的內存塊中,之后,清除正在使用的內存塊中的所有對象,交換兩個內存的角色,完成垃圾回收。
Java 堆內存并不需要按照1:1的比例劃分內存空間,而是將內存分為一塊較大的Eden空間和兩塊較小的Survivor空間,每次使用Eden和其中的一塊Survivor。當回收時,將Eden和Survivor中還存活著的對象一次性地拷貝到另外一個Survivor空間上,最后清理掉Eden和剛才用過的Survivor的空間。
HotSpot虛擬機默認Eden:Survivor From ::Survivor To 的大小比例是8:1:1(可以通過-SurvivorRattio來配置),也就是每次新生代中可用內存空間為整個新生代容量的90%,只有10%的內存會被“浪費”。
當然,98%的對象可回收只是一般場景下的數據,我們沒有辦法保證回收都只有不多于10%的對象存活,當Survivor空間不夠用時,需要依賴其他內存(這里指老年代)進行分配擔保。
優缺點:
復制算法相對標記壓縮算法來說更簡潔高效,但它的缺點也顯而易見,它不適合用于存活對象多的情況,因為那樣需要復制的對象很多,復制性能較差,所以復制算法往往用于內存空間中新生代的垃圾回收,因為新生代中存活對象較少,復制成本較低。它另外一個缺點是內存空間占用成本高,因為它基于兩份內存空間做對象復制,在非垃圾回收的周期內只用到了一份內存空間,內存利用率較低。
標記整理/壓縮算法(老年代的GC)
標記:它的第一個階段與標記/清除算法是一模一樣的,均是遍歷GC Roots,然后將存活的對象標記。
整理:移動所有存活的對象,且按照內存地址次序依次排列,然后將末端內存地址以后的內存全部回收。因此,第二階段才稱為整理階段。
上圖中可以看到,標記的存活對象將會被整理,按照內存地址依次排列,而未被標記的內存會被清理掉。如此一來,當我們需要給新對象分配內存時,JVM只需要持有一個內存的起始地址即可,這比維護一個空閑列表顯然少了許多開銷。
優點:
因為標記清除算法會造成內存的不連續,所以標記整理(壓縮)算在標記清除算法的基礎上,增加了整理過程,解決了標記清除算法內存不連續的問題。同時也消除了復制算法當中,內存減半的高額代價。
缺點:
標記整理(壓縮)也會產生“stop the world”,不能和java程序并發執行。在壓縮過程中一些對象內存地址會發生改變,java程序只能等待壓縮完成后才能繼續。
標記-清除算法、復制算法、標記整理算法總結
在GC線程開啟時,或者說GC過程開始時,它們都要暫停應用程序(stop the world)。
它們的區別如下:(>表示前者要優于后者,=表示兩者效果一樣)
(1)效率:復制算法>標記/整理算法>標記/清除算法(此處的效率只是簡單的對比時間復雜度,實際情況不一定如此)。
(2)內存整齊度:復制算法=標記/整理算法>標記/清除算法。
(3)內存利用率:標記/整理算法=標記/清除算法>復制算法。
- 可以看到標記/清除算法是比較落后的算法了,但是后兩種算法卻是在此基礎上建立的。
- 時間與空間不可兼得。
分代收集算法(新生代的GC+老年代的GC)
當前商業虛擬機都采用分代收集算法。
分代的垃圾回收策略,是基于這樣一個事實:不同的對象的生命周期是不一樣的。因此,不同生命周期的對象可以采取不同的收集方式,以便提高回收效率。
在新生代,每次垃圾收集器都發現有大批對象死去,只有少量的存活,那就選擇復制算法,只需要付出少量存活對象的復制成本就可以完成收集。 在老年代因為對象的存活率較高、沒有額外空間對它進行分配擔保,就必須使用“標記-清除”或者“標記-整理”算法進行回收。
注:老年代的對象中,有一小部分是因為在新生代回收時,老年代做擔保,進來的對象;絕大部分對象是因為很多次GC都沒有被回收掉而進入老年代。
總結
以上是生活随笔為你收集整理的JVM-05垃圾收集Garbage Collection(中)【垃圾收集算法】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JVM-04垃圾收集Garbage Co
- 下一篇: JVM-07垃圾收集Garbage Co