1. 程式人生 > >JVM GC演算法 CMS 詳解(轉)

JVM GC演算法 CMS 詳解(轉)

前言

CMS,全稱Concurrent Low Pause Collector,是jdk1.4後期版本開始引入的新gc演算法,在jdk5和jdk6中得到了進一步改進,它的主要適合場景是對響應時間的重要性需求 大於對吞吐量的要求,能夠承受垃圾回收執行緒和應用執行緒共享處理器資源,並且應用中存在比較多的長生命週期的物件的應用。CMS是用於對tenured generation的回收,也就是年老代的回收,目標是儘量減少應用的暫停時間,減少full gc發生的機率,利用和應用程式執行緒併發的垃圾回收執行緒來標記清除年老代。在我們的應用中,因為有快取的存在,並且對於響應時間也有比較高的要求,因此希 望能嘗試使用CMS來替代預設的server型JVM使用的並行收集器,以便獲得更短的垃圾回收的暫停時間,提高程式的響應性。

CMS收集週期


CMS並非沒有暫停,而是用兩次短暫停來替代序列標記整理演算法的長暫停,它的收集週期是這樣:
初始標記(CMS-initial-mark) -> 併發標記(CMS-concurrent-mark) -> 重新標記(CMS-remark) -> 併發清除(CMS-concurrent-sweep) ->併發重設狀態等待下次CMS的觸發(CMS-concurrent-reset)。
其中的1,3兩個步驟需要暫停所有的應用程式執行緒的。第一次暫停從root物件開始標記存活的物件,這個階段稱為初始標記;第二次暫停是在併發標記之後, 暫停所有應用程式執行緒,重新標記併發標記階段遺漏的物件(在併發標記階段結束後物件狀態的更新導致)。第一次暫停會比較短,第二次暫停通常會比較長,並且 remark這個階段可以並行標記。

而併發標記、併發清除、併發重設階段的所謂併發,是指一個或者多個垃圾回收執行緒和應用程式執行緒併發地執行,垃圾回收執行緒不會暫停應用程式的執行,如果你有多於一個處理器,那麼併發收集執行緒將與應用執行緒在不同的處理器上執行,顯然,這樣的開銷就是會降低應用的吞吐量。Remark階段的並行,是指暫停了所有應用程式後,啟動一定數目的垃圾回收程序進行並行標記,此時的應用執行緒是暫停的。

CMS的young generation的回收採用的仍然是並行複製收集器,這個跟Paralle gc演算法是一致的。

引數介紹

1、啟用CMS:-XX:+UseConcMarkSweepGC。
2。CMS預設啟動的回收執行緒數目是 (ParallelGCThreads + 3)/4) ,如果你需要明確設定,可以通過-XX:ParallelCMSThreads=20來設定,其中ParallelGCThreads是年輕代的並行收集執行緒數
3、CMS是不會整理堆碎片的,因此為了防止堆碎片引起full gc,通過會開啟CMS階段進行合併碎片選項:-XX:+UseCMSCompactAtFullCollection,開啟這個選項一定程度上會影響效能,阿寶的blog裡說也許可以通過配置適當的CMSFullGCsBeforeCompaction來調整效能,未實踐。
4.為了減少第二次暫停的時間,開啟並行remark: -XX:+CMSParallelRemarkEnabled。如果remark還是過長的話,可以開啟-XX:+CMSScavengeBeforeRemark選項,強制remark之前開始一次minor gc,減少remark的暫停時間,但是在remark之後也將立即開始又一次minor gc。

5.為了避免Perm區滿引起的full gc,建議開啟CMS回收Perm區選項:
+CMSPermGenSweepingEnabled -XX:+CMSClassUnloadingEnabled

6.預設CMS是在tenured generation沾滿68%的時候開始進行CMS收集,如果你的年老代增長不是那麼快,並且希望降低CMS次數的話,可以適當調高此值:
-XX:CMSInitiatingOccupancyFraction=80

這裡修改成80%沾滿的時候才開始CMS回收。

7.年輕代的並行收集執行緒數預設是(cpu <= 8) ? cpu : 3 + ((cpu * 5) / 8),如果你希望降低這個執行緒數,可以通過-XX:ParallelGCThreads= N 來調整。

8.進入重點,在初步設定了一些引數後,例如:

-server -Xms1536m -Xmx1536m -XX:NewSize=256m -XX:MaxNewSize=256m -XX:PermSize=64m 
-XX:MaxPermSize=64m -XX:-UseConcMarkSweepGC -XX:+UseCMSCompactAtFullCollection 
-XX:CMSInitiatingOccupancyFraction=80 -XX:+CMSParallelRemarkEnabled 
-XX:SoftRefLRUPolicyMSPerMB=0 


需要在生產環境或者壓測環境中測量這些引數下系統的表現,這時候需要開啟GC日誌檢視具體的資訊,因此加上引數:

-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:/home/test/logs/gc.log


在執行相當長一段時間內檢視CMS的表現情況,CMS的日誌輸出類似這樣:

複製程式碼
4391.322: [GC [1 CMS-initial-mark: 655374K(1310720K)] 662197K(1546688K), 0.0303050 secs] [Times: user=0.02 sys=0.02, real=0.03 secs] 
4391.352: [CMS-concurrent-mark-start] 
4391.779: [CMS-concurrent-mark: 0.427/0.427 secs] [Times: user=1.24 sys=0.31, real=0.42 secs] 
4391.779: [CMS-concurrent-preclean-start] 
4391.821: [CMS-concurrent-preclean: 0.040/0.042 secs] [Times: user=0.13 sys=0.03, real=0.05 secs] 
4391.821: [CMS-concurrent-abortable-preclean-start] 
4392.511: [CMS-concurrent-abortable-preclean: 0.349/0.690 secs] [Times: user=2.02 sys=0.51, real=0.69 secs] 
4392.516: [GC[YG occupancy: 111001 K (235968 K)]4392.516: [Rescan (parallel) , 0.0309960 secs]4392.547: [weak refs processing, 0.0417710 secs] [1 CMS-remark: 655734K(1310720K)] 766736K(1546688K), 0.0932010 secs] [Times: user=0.17 sys=0.00, real=0.09 secs] 
4392.609: [CMS-concurrent-sweep-start] 
4394.310: [CMS-concurrent-sweep: 1.595/1.701 secs] [Times: user=4.78 sys=1.05, real=1.70 secs] 
4394.310: [CMS-concurrent-reset-start] 
4394.364: [CMS-concurrent-reset: 0.054/0.054 secs] [Times: user=0.14 sys=0.06, real=0.06 secs] 
複製程式碼

其中可以看到CMS-initial-mark階段暫停了0.0303050秒,而CMS-remark階段暫停了0.0932010秒,因此兩次暫停的總共時間是0.123506秒,也就是123毫秒左右。兩次短暫停的時間之和在200以下可以稱為正常現象。

但是你很可能遇到兩種fail引起full gc:Prommotion failed和Concurrent mode failed。

Prommotion failed的日誌輸出大概是這樣:

[ParNew (promotion failed): 320138K->320138K(353920K), 0.2365970 secs]42576.951: [CMS: 1139969K->1120688K( 
166784K), 9.2214860 secs] 1458785K->1120688K(2520704K), 9.4584090 secs] 


這個問題的產生是由於救助空間不夠,從而向年老代轉移物件,年老代沒有足夠的空間來容納這些物件,導致一次full gc的產生。解決這個問題的辦法有兩種完全相反的傾向:增大救助空間、增大年老代或者去掉救助空間。 增大救助空間就是調整-XX:SurvivorRatio引數,這個引數是Eden區和Survivor區的大小比值,預設是32,也就是說Eden區是 Survivor區的32倍大小,要注意Survivo是有兩個區的,因此Surivivor其實佔整個young genertation的1/34。調小這個引數將增大survivor區,讓物件儘量在survitor區呆長一點,減少進入年老代的物件。去掉救助空 間的想法是讓大部分不能馬上回收的資料儘快進入年老代,加快年老代的回收頻率,減少年老代暴漲的可能性,這個是通過將-XX:SurvivorRatio 設定成比較大的值(比如65536)來做到。在我們的應用中,將young generation設定成256M,這個值相對來說比較大了,而救助空間設定成預設大小(1/34),從壓測情況來看,沒有出現prommotion failed的現象,年輕代比較大,從GC日誌來看,minor gc的時間也在5-20毫秒內,還可以接受,因此暫不調整。

Concurrent mode failed的產生是由於CMS回收年老代的速度太慢,導致年老代在CMS完成前就被沾滿,引起full gc,避免這個現象的產生就是調小-XX:CMSInitiatingOccupancyFraction引數的值,讓CMS更早更頻繁的觸發,降低年老代被沾滿的可能。我們的應用暫時負載比較低,在生產環境上年老代的增長非常緩慢,因此暫時設定此引數為80。在壓測環境下,這個引數的表現還可以,沒有出現過Concurrent mode failed。

相關推薦

JVM GC演算法 CMS ()

前言CMS,全稱Concurrent Low Pause Collector,是jdk1.4後期版本開始引入的新gc演算法,在jdk5和jdk6中得到了進一步改進,它的主要適合場景是對響應時間的重要性需求 大於對吞吐量的要求,能夠承受垃圾回收執行緒和應用執行緒共享處理器資源,並且應用中存在比較多的長生命週期的

JVM結構、GC工作機制

固定 本地方法棧 內存池 為什麽 water aml 並且 兩種 數據區 轉自:http://blog.csdn.net/tonytfjing/article/details/44278233 JVM結構、內存分配、垃圾回收算法、垃圾收集器。下面我們一一來看。 一、JVM結

JVMGc工作機制

相同 生命 棧幀 VM 每次 失效 劃分 地址 .com JVM主要包括四個部分: 類加載器(ClassLoad) 執行引擎 內存區: 本地方法接口:類似於jni調本地native方法 內存區包括四個部分: 1.方法區:包含了靜態變量、常量池、構造函數等

業余草分享面試題,JVM結構、GC工作機制

影響 根節點 tac 關註 共享 產生 我想 tar 效果 題外話:最近在應聘阿裏2015暑期實習,感觸頗多。機會總是留給有準備的人的,所以平常一定要註意知識的鞏固和積累。知識的深度也要有一定的理解,不比別人知道的多,公司幹嘛選你?關於JVM和GC,我相信學java的絕大部

[Network Architecture]DPN(Dual Path Network)演算法()

https://blog.csdn.net/u014380165/article/details/75676216 論文:Dual Path Networks 論文連結:https://arxiv.org/abs/1707.01629 程式碼:https://github.com/cypw/DPN

JVM監控命令()

JVM監控命令基本就是 jps、jstack、jmap、jhat、jstat 幾個命令的使用就可以了   JDK本身提供了很多方便的JVM效能調優監控工具,除了整合式的VisualVM和jConsole外,還有jps、jstack、jmap、jhat、jstat

)gzib等壓縮演算法原理

gzip 、zlib以及圖形格式png,使用的壓縮演算法都是deflate演算法。從gzip的原始碼中,我們瞭解到了defalte演算法的原理和實現。我閱讀的gzip版本為 gzip-1.2.4。下面我們將要對deflate演算法做一個分析和說明。首先簡單介紹一下基本原理,然後詳細的介紹實現。 1 gz

JVM -verbose引數()

java -verbose[:class|gc|jni] 在輸出裝置上顯示虛擬機器執行資訊。 1.java -verbose:class 在程式執行的時候有多少類被載入!你可以用verbose:class來監視,在命令列輸入java -verbose:class XXX

Rsyslog配置文件()

安裝 權限 lines true time cor optional tex 以及 最近在搭建日誌審計服務器,使用了rsyslog,發現這篇文章很有用,收藏一下。 原文鏈接:http://my.oschina.net/0757/blog/198329 具體內容: 非常詳

Buffer類的()

iteye 原始數據類型 pub bst exception 如何 數字 硬件 final Buffer 類是 java.nio 的構造基礎。一個 Buffer 對象是固定數量的數據的容器,其作用是一個存儲器,或者分段運輸區,在這裏,數據可被存儲並在之後用於檢索。緩沖區可以

UML類圖與類的關系--

position 好的 -a erp 生命 靜態 pan 雙向 單選 http://www.uml.org.cn/oobject/201104212.asp 原文地址 UML類圖與類的關系詳解 2011-04-21 來源:網絡

CentOS 7.1下SSH遠程登錄服務器-

info which 開啟 如何 pty wan public keygen ger 轉自:http://www.linuxidc.com/Linux/2016-03/129204.htm 一、明文傳輸與加密傳輸 明文傳輸:當我們的數據包在網絡上傳輸的時候,以數據包的原

lucene、lucene.NET詳細使用與優化[]

構造 bitset 更多 隱患 .net wrapper 屬性設置 似的 擔心 1 lucene簡介1.1 什麽是luceneLucene是一個全文搜索框架,而不是應用產品。因此它並不像www.baidu.com 或者google Desktop那麽拿來就能用,它只是提供了

Java垃圾回收(GC)機制

nbsp 引用計數 維護 png 對象 最新 新的 com 前沿 垃圾回收算法有兩種,根據不同的虛擬機策略不同 1、引用計數法 2、可達性分析法 由於我們平常使用的hotspot虛擬機用的是第二種。 那哪些是可達的呢? 這個算法的基本思想是通過一系列稱為“GC Roots”

c++拷貝函數()

light clu 默認 fun 編譯 存在 自動生成 pri 指針成員 一. 什麽是拷貝構造函數 首先對於普通類型的對象來說,它們之間的復制是很簡單的,例如 int a = 100; int b = a; 而類對象與普通對象不同,類對象內部結構一般

KM算法[]

分割 貪心 方便 itl 兩個 最大權值匹配 之間 保留 top KM算法詳解 原帖鏈接:http://www.cnblogs.com/zpfbuaa/p/7218607.html#_label0 閱讀目錄 二分圖博客推薦 匈牙利算法步驟 匈牙利算

MANIFEST.MF 文件內容完全()

做的 software 多功能 keys 要求 ext pmd 獲取 可執行 打開Java的JAR文件我們經常可以看到文件中包含著一個META-INF目錄, 這個目錄下會有一些文件,其中必有一個MANIFEST.MF,這個文件描述了該Jar文件的很多信息,下面將詳細介紹MA

Flume日誌收集系統架構--

with 指定 mwl 裏程碑 工程 生命 數據接收 dba -i 2017-09-06 朱潔 大數據和雲計算技術 任何一個生產系統在運行過程中都會產生大量的日誌,日誌往往隱藏了很多有價值的信息。在沒有分析方法之前,這些日誌存儲一段時間後就會被清理。隨著技術的發展和

macOS開發之NSTableView的應用 -

validate creat 編寫 移除 分割線 gen styles 如果 bool 傳送門:https://my.oschina.net/u/2340880/blog/886861 摘要: NSTableView是AppKit中的表視圖控件,是macOS開發中非常重要的

SSD(single shot multibox detector)算法及Caffe代碼[]

作者 3.4 pdf 論文 做了 對比度調整 覆蓋 eccv 添加 這篇博客主要介紹SSD算法,該算法是最近一年比較優秀的object detection算法,主要特點在於采用了特征融合。 論文:SSD single shot multibox detector論文鏈接:h