從前文JVM垃圾回收幾種常見算法和常見收集器我們知道,CMS是老年代垃圾收集器。CMS 收集器主要關注系統停頓時間。CMS 是 Concurrent Mark Sweep 的縮寫,意為並發標記清除,從名稱上可以得知,它使用的是標記-清除算法,同時它又是一個使用多線程並發回收的垃圾收集器。它可以與Serial收集器和parNew收集器搭配使用。
CMS工作時,主要步驟有:初始標記、並發標記、重新標記、並發清除和並發重置。其中初始標記和重新標記是獨占系統資源的,而並發標記、並發清除和並發重置是可以和用戶線程一起執行的。因此,從整體上來說,CMS收集不是獨占式的,它可以在應用程序運行過程中進行垃圾回收。
根據標記-清除算法,初始標記、並發標記和重新標記都是為了標記出需要回收的對象。並發清理則是在標記完成后,正式回收垃圾對象;並發重置是指在垃圾回收完成后,重新初始化CMS數據結構和數據,為下一次垃圾回收做好准備。
CMS收集器在其主要的工作階段雖然沒有暴力地徹底暫停應用程序線程,但是由於它和應用程序線程並發執行,相互搶占CPU,所以在CMS執行期內對應用程序吞吐量造成一定影響。CMS 默認啟動的線程數是 (ParallelGCThreads+3)/4),ParallelGCThreads 是新生代並行收集器的線程數,也可以通過-XX:ParallelCMSThreads參數手工設定CMS的線程數量。當CPU資源比較緊張時,受到CMS收集器線程的影響,應用程序的性能在垃圾回收階段可能會非常糟糕。
由於CMS收集器不是獨占式的回收器,在CMS回收過程中,應用程序仍然在不停地工作。在應用程序工作過程中,又會不斷地產生垃圾。這些新生成的垃圾在當前CMS回收過程中是無法清除的。同時,因為應用程序沒有中斷,所以在CMS回收過程中,還應該確保應用程序有足夠的內存可用。因此,CMS收集器不會等待堆內存飽和時才進行垃圾回收,而是當前堆內存使用率達到某一閾值時,便開始進行回收,以確保應用程序在CMS工作過程中依然有足夠的空間支持應用程序運行。這個回收閾值可以使用-XX:CMSInitiatingOccupancyFraction來指定,默認是 68。即當老年代的空間使用率達到 68%時,會執行一次CMS回收。如果應用程序的內存使用率增長很快,在CMS的執行過程中,已經出現了內存不足的情況,此時CMS回收將會失敗,JVM將啟動老年代串行收集器進行垃圾回收。如果這樣,應用程序將完全中斷,直到垃圾收集完成,這時,應用程序的停頓時間可能很長。因此,根據應用程序的特點,可以對-XX:CMSInitiatingOccupancyFraction 進行調優。如果內存增長緩慢,則可以設置一個稍大的值,大的閾值可以有效降低CMS的觸發頻率,減少老年代回收的次數可以較為明顯地改善應用程序性能。反之,如果應用程序內存使用率增長很快,則應該降低這個閾值,以避免頻繁觸發老年代串行收集器。 標記-清除算法將會造成大量內存碎片,離散的可用空間無法分配較大的對象。在這種情況下,即使堆內存仍然有較大的剩余空間,也可能會被迫進行一次垃圾回收,以換取一塊可用的連續內存,這種現象對系統性能是相當不利的。為了解決這個問題,CMS收集器還提供了幾個用於內存壓縮整理的算法。
-
-XX:+UseCMSCompactAtFullCollection 使CMS在垃圾收集完成后,進行一次內存碎片整理。內存碎片的整理並不是並發進行的。
-
-XX:CMSFullGCsBeforeCompaction 用於設定進行多少次CMS回收后,進行一次內存整理。
-
-XX:+CMSScavengeBeforeRemark 最終標記之前強制進行一個Minor GC。
-
-XX:+UseConcMarkSweepGC 可以要求新生代使用parNew,老年代使用CMS。
-
-XX:+UseCMSInitiatingOccupancyOnly
指定CMSInitiatingOccupancyFraction的回收閾值,如果不指定,jvm僅在第一次使用設定值,后續則自動調整。
-
-XX:+CMSParallelRemarkEnabled 並行運行最終標記階段,加快最終標記的速度
-
-XX:+CMSClassUnloadingEnabled 讓CMS可以收集永久帶,默認不會收集
-
-XX:+ExplicitGCInvokesConcurrent 當調用System.gc()的時候,執行並行gc,只有在CMS或者G1下該參數才有效
CMS對CPU的資源非常敏感。由於采用標記-清除算法會存在空間碎片的問題,導致大對象無法分配空間不得不提前觸發一次full gc的情況。而且無法處理浮動垃圾,可能出現Concurrent Model Failure失敗而導致另一次full gc的情況。
垃圾回收篇幅過長,下文繼續講解最后的內容G1收集器。