JVM垃圾回收之CMS收集器

從前文 我們知道,CMS是老年代垃圾收集器。CMS 收集器主要關注系統停頓時間。CMS 是 Concurrent Mark Sweep 的縮寫,意為併發標記清除,從名稱上可以得知,它使用的是標記-清除算法,同時它又是一個使用多線程併發回收的垃圾收集器。它可以與

Serial收集器和parNew收集器搭配使用。

JVM垃圾回收之CMS收集器

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收集器


分享到:


相關文章: