以前已經講過了很多有關 GC 的內容,今天準備將以前沒有細講的部分進行補充,首先要提到的就是垃圾收集器。 git
基礎的回收方式有三種:清除
、壓縮
、複製
,衍生出來的垃圾收集器有:github
新生代收集器,使用中止複製算法,使用一個線程進行 GC ,串行,其它工做線程暫停。算法
使用-XX:+UseSerialGC
開關來控制使用Serial + Serial Old
模式運行進行內存回收(這也是虛擬機在 Client 模式下運行的默認值)。數據結構
新生代收集器,使用中止複製算法,Serial 收集器的多線程版,用多個線程進行 GC ,並行,其它工做線程暫停,關注縮短垃圾收集時間。多線程
使用-XX:+UseParNewGC
開關來控制使用ParNew + Serial Old
收集器組合收集內存;使用-XX:ParallelGCThreads
來設置執行內存回收的線程數。併發
新生代收集器,使用中止複製算法,關注 CPU 吞吐量,即運行用戶代碼的時間/總時間
,好比:JVM 運行 100 分鐘,其中運行用戶代碼 99 分鐘,垃 圾收集 1 分鐘,則吞吐量是 99% ,這種收集器能最高效率的利用 CPU ,適合運行後臺運算(其餘關注縮短垃圾收集時間的收集器,如 CMS ,等待時間不多,因此適 合用戶交互,提升用戶體驗)。性能
使用-XX:+UseParallelGC
開關控制使用Parallel Scavenge + Serial Old
收集器組合回收垃圾(這也是在 Server 模式下的默認值);使用-XX:GCTimeRatio
來設置用戶執行時間佔總時間的比例,默認 99 ,即 1% 的時間用來進行垃圾回收。使用-XX:MaxGCPauseMillis
設置 GC 的最大停頓時間(這個參數只對 Parallel Scavenge 有效),用開關參數-XX:+UseAdaptiveSizePolicy
能夠進行動態控制,如自動調整 Eden / Survivor 比例,老年代對象年齡,新生代大小等,這個參數在 ParNew 下沒有。spa
老年代收集器,單線程收集器,串行,使用標記-整理
算法,使用單線程進行GC,其它工做線程暫停(注意:在老年代中進行標記-整理
算法清理,也須要暫停其它線程),在JDK1.5以前,Serial Old 收集器與 ParallelScavenge 搭配使用。線程
整理的方法是 Sweep (清除)和 Compact (壓縮),清除是將廢棄的對象幹掉,只留倖存的對象,壓縮是移動對象,將空間填滿保證內存分爲2塊,一塊全是對象,一塊空閒),日誌
老年代收集器,多線程,並行,多線程機制與 Parallel Scavenge 差不錯,使用標記-整理
算法,在 Parallel Old 執行時,仍然須要暫停其它工做線程。
Parallel Old 收集器的整理,與 Serial Old 不一樣,這裏的整理是Copy(複製)和Compact(壓縮),複製的意思就是將倖存的對象複製到預先準備好的區域,而不是像Sweep(清除)那樣清除廢棄的對象。
Parallel Old 在多核計算中頗有用。 Parallel Old 出現後(JDK 1.6),與 Parallel Scavenge 配合有很好的效果,充分體現 Parallel Scavenge 收集器吞吐量優先的效果。使用-XX:+UseParallelOldGC
開關控制使用Parallel Scavenge + Parallel Old
組合收集器進行收集。
全稱 Concurrent Mark Sweep,老年代收集器,致力於獲取最短回收停頓時間(即縮短垃圾回收的時間),使用標記-清除
算法,多線程,優勢是併發收集(用戶線程能夠和 GC 線程同時工做),停頓小。
使用-XX:+UseConcMarkSweepGC
進行ParNew + CMS + Serial Old
進行內存回收,優先使用ParNew + CMS
(緣由見後面),當用戶線程內存不足時,採用備用方案Serial Old
收集。
首先來看一下 CMS 是在什麼狀況下進行 GC:
-XX:CMSInitiatingOccupancyFraction
、-XX:+UseCMSInitiatingOccupancyOnly
來決定什麼時間開始垃圾收集。 -XX:+UseCMSInitiatingOccupancyOnly
,那麼只有當老年代佔用確實達到了-XX:CMSInitiatingOccupancyFraction
參數所設定的比例時纔會觸發 CMS GC。 -XX:+UseCMSInitiatingOccupancyOnly
,那麼系統會根據統計數據自行決定何時觸發 CMS GC。所以有時會遇到設置了 80% 比例才 CMS GC,可是 50% 時就已經觸發了,就是由於這個參數沒有設置的緣由。 CMS GC 的執行過程,具體來講就是:
該階段是 stop the world 階段,所以此階段標記的對象只是從 root 集最直接可達的對象。
此階段會打印 1 條日誌:CMS-initial-mark:961330K(1572864K),指標記時,老年代的已用空間和總空間
此階段是和應用線程併發執行的,所謂併發收集器指的就是這個,主要做用是標記可達的對象,此階段不須要用戶線程停頓。
此階段會打印 2 條日誌:CMS-concurrent-mark-start,CMS-concurrent-mark
此階段主要是進行一些預清理,由於標記和應用線程是併發執行的,所以會有些對象的狀態在標記後會改變,此階段正是解決這個問題。由於以後的 CMS-remark 階段也會 stop the world,爲了使暫停的時間儘量的小,也須要 preclean 階段先作一部分工做以節省時間。
此階段會打印 2 條日誌:CMS-concurrent-preclean-start,CMS-concurrent-preclean
此階段的目的是使 CMS GC 更加可控一些,做用也是執行一些預清理,以減小 CMS-remark 階段形成應用暫停的時間。
此階段涉及幾個參數:
-XX:CMSMaxAbortablePrecleanTime:當 abortable-preclean 階段執行達到這個時間時纔會結束。
-XX:CMSScheduleRemarkEdenSizeThreshold(默認2m):控制 abortable-preclean 階段何時開始執行,即當年輕代使用達到此值時,纔會開始 abortable-preclean 階段。
-XX:CMSScheduleRemarkEdenPenetratio(默認50%):控制 abortable-preclean 階段何時結束執行。複製代碼
此階段會打印 3 條日誌:CMS-concurrent-abortable-preclean-start,CMS-concurrent-abortable-preclean,CMS:abort preclean due to time XXX
此階段暫停應用線程,停頓時間比並發標記小得多,但比初始標記稍長,由於會對全部對象進行從新掃描並標記。
此階段會打印如下日誌:
此階段進行併發的垃圾清理。
此階段是爲下一次 CMS GC 重置相關數據結構。
CMS 的收集過程,歸納一下就是:2 次標記,2 次預清除,1 次從新標記,1 次清除。
在CMS清理過程當中,只有初始標記和從新標記須要短暫停頓用戶線程,併發標記和併發清除都不須要暫停用戶線程,所以效率很高,很適合高交互的場合。
CMS也有缺點
,它須要消耗額外的 CPU 和內存資源。在 CPU 和內存資源緊張,會加劇系統負擔(CMS 默認啓動線程數爲( CPU數量 + 3 ) / 4 )。
另外,在併發收集過程當中,用戶線程仍然在運行,仍然產生內存垃圾,因此可能產生「浮動垃圾」(本次沒法清理,只能下一次Full GC才清理)。所以在 GC 期間,須要預留足夠的內存給用戶線程使用。
因此使用 CMS 的收集器並非老年代滿了才觸發 Full GC ,而是在使用了一大半(默認 68% ,即 2/3 ,使用-XX:CMSInitiatingOccupancyFraction
來設置)的時候就要進行 Full GC。若是用戶線程消耗內存不是特別大,能夠適當調高-XX:CMSInitiatingOccupancyFraction
以下降 GC 次數,提升性能。若是預留的用戶線程內存不夠,則會觸發 Concurrent Mode Failure,此時,將觸發備用方案:使用 Serial Old 收集器進行收集,但這樣停頓時間就長了,所以-XX:CMSInitiatingOccupancyFraction
不宜設的過大。
還有,CMS 採用的是標記-清除
算法,會致使內存碎片的產生,可使用-XX:+UseCMSCompactAtFullCollection
來設置是否在 Full GC 以後進行碎片整理,用-XX:CMSFullGCsBeforeCompaction
來設置在執行多少次不壓縮的 Full GC 以後,來一次帶壓縮的 Full GC。
併發收集:
指用戶線程與GC線程同時執行(不必定是並行,可能交替,但整體上是在同時執行的),不須要停頓用戶線程(其實在 CMS 中用戶線程仍是須要停頓的,只是很是短,GC 線程在另外一個 CPU 上執行);
並行收集:
指多個 GC 線程並行工做,但此時用戶線程是暫停的;
因此,Serial 是串行的,Parallel 收集器是並行的,而 CMS 收集器是併發的。
今天瞭解了一下普通的垃圾收集器,而且詳細介紹了 CMS,其特性實際上是基於普通的垃圾算法,增長了預處理、預清除的過程,所以效率更加優越。固然它也有本身的缺點,更加消耗資源,所以在選用的時候須要結合實際場景。
有興趣的話能夠訪問個人博客或者關注個人公衆號、頭條號,說不定會有意外的驚喜。