(5) Java GC算法及種類

GC算法主要有以下三種方法(都是以GC Roots可達性爲依據,引用計數算法實現簡單,但由於存在循環引用問題,故已不採用,詳見:Java GC(概述)

(1).複製收集算法

針對Young區,依次掃描這個區的所有可達對象(如何確定可達對象,請參考前一節),掃描只掃描GC維護的一張對象關係有向圖(以下稱爲可達對象鏈),只要在這個圖上的,就將這個對象複製到另一個區域(實現這種算法需要堆內存保留一個與Young區大小一樣的區域),原先的Eden區對象,移到From區,From區移到To區,有必要的話,將對象移到Old區(區域劃分,見Java內存結構),原先內存全部清空,作爲下一次GC用。

優缺點:只需遍歷可達的對象,不用訪問不可達對象,遍歷少,但需要巨大的複製成本和較多的內存。

(2).標記清除算法

遍歷可達對象鏈,對這些對象進行標記,下次,遍歷整個區域的對象,沒有標記的清除。

優缺點:不需要額外空間,但是遍歷空間花費大,而且會產生大量內存碎片

(3).標記整理算法

前二者的結合,遍歷可達對象鏈,標記這些對象,再按順序將這些對象合併到一塊內存上,比如,有1、2、3、4、5、6、7、8塊連續內存對象,其中2,5,8是可達鏈上對象,標記整理算法的做法是:先標記他們,再從1開始遍歷,1不是,到2,2是,將2複製到1,2標記清除,再遍歷3,4,不是,遍歷5,是,將5複製到2,依次如此,最後得到1,2,3有用內存,後面內存就被清除了。

優缺點:相對標記清除來說,沒有了內存碎片,但是遍歷花費仍然很大。

實際上,GC根據堆內存空間不同區域,採用不同的算法回收:

Young區:存活的對象較少,複製代價小,但次數多,採用複製收集算法;

Old區和方法區:對象存活較多,次數少,較慢,採用標記清除或標記整理算法。

以上,是GC的具體算法,即回收內存的做法,GC回收器種類實現上也有很多種。

再說明各種GC回收器之前,先說明下GC回收器的衡量指標:

1.Throughput(吞吐量):所有沒有花在執行GC上的時間佔總運行時間的比重。

2.Pauses(暫停):當GC在運行時程序的暫停次數。或者是在感興趣的暫停次數中,暫停的平均時長和最大時長。

3.Footprint(足跡?):當前使用的堆內存大小(算法所有花費的額外空間)。

4.Promptness(及時性):不再使用的對象多久能被清除掉並釋放其內存。

(1).串行垃圾回收器

GC線程只有一個,它會暫停所有工作線程,一個一個內存區域來收集,不適合服務器環境。通過JVM命令-XX:+UseSerialGC可以使用串行垃圾回收器。串行回收器也有兩種:1.Serial:只對新生代使用;2.Serial Old:只對老年代使用,採用的算法不一樣(一般作爲CMS的替補)

(2).並行垃圾回收器

GC使用多線程進行垃圾回收。通過JVM命令-XX:+UseParallGC可以使用並行垃圾回收器。並行回收器有三種:1.ParNew,作用於新生代; 2.Parallel Scavenge 作用於新生代,但以吞吐量爲主;3.Parallel Old,作用於老年代,也已吞吐量爲主,配合2使用。

(3).併發標記掃描垃圾回收器(CMS)

多線程,標記清理(Full GC的時候用)通過JVM命令 -XX:+UseConcMarkSweepGC使用, 主要用於老生代,策略爲:

老代只有兩次短暫停,其他時間應用程序與收集線程併發的清除。採用兩次短暫停來替代標記整理算法的長暫停,它的收集週期:  

初始標記(CMS-initial-mark) -> 併發標記(CMS-concurrent-mark) -> 重新標記(CMS-remark)-> 併發清除(CMS-concurrent-sweep) ->併發重設狀態等待下次CMS的觸發(CMS-concurrent-reset)。

它的主要適合場景是對響應時間的重要性需求大於對吞吐量的要求,能夠承受垃圾回收線程和應用線程共享處理器資源,並且應用中存在比較多的長生命週期的對象的應用。但CMS收集算法在最爲耗時的內存區域遍歷時採用多線程併發操作,對於服務器CPU資源不夠的情況下,其實對性能是沒有提升的,反而會導致系統吞吐量的下降;

(4).G1垃圾回收器

適用於堆內存很大的情況,它將對內存分割成不同的區域,並且併發的對其進行回收,回收後對剩餘內存壓縮,標記整理,服務器端適用。

​發現一篇,針對GC垃圾回收的詳細優質博客,可以參考:JVM 調優和垃圾回收器說明(zhuangyalei)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章