<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢蝶

    生活、程序、未來
       :: 首頁 ::  ::  :: 聚合  :: 管理

    CMS gc實踐總結(糾正并發線程數)

    Posted on 2009-09-22 02:10 dennis 閱讀(18277) 評論(1)  編輯  收藏 所屬分類: java
        首先感謝阿寶同學的幫助,我才對這個gc算法的調整有了一定的認識,而不是停留在過去僅僅了解的階段。在讀過sun的文檔和跟阿寶討論之后,做個小小的總結。
        CMS,全稱Concurrent Low Pause Collector,是jdk1.4后期版本開始引入的新gc算法,在jdk5和jdk6中得到了進一步改進,它的主要適合場景是對響應時間的重要性需求大于對吞吐量的要求,能夠承受垃圾回收線程和應用線程共享處理器資源,并且應用中存在比較多的長生命周期的對象的應用。CMS是用于對tenured generation的回收,也就是年老代的回收,目標是盡量減少應用的暫停時間,減少full gc發生的幾率,利用和應用程序線程并發的垃圾回收線程來標記清除年老代。在我們的應用中,因為有緩存的存在,并且對于響應時間也有比較高的要求,因此希望能嘗試使用CMS來替代默認的server型JVM使用的并行收集器,以便獲得更短的垃圾回收的暫停時間,提高程序的響應性。
        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.年輕代的并行收集線程數默認是(ncpus <= 8) ? ncpus : 3 + ((ncpus * 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(
    2166784K), 
    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。


    參考資料:
    》 by 江南白衣
    《記一次Java GC調整經歷》
    1,2 by Arbow
    Java SE 6 HotSpot[tm] Virtual Machine Garbage Collection Tuning
    Tuning Garbage Collection with the 5.0 JavaTM Virtual Machine

      



    評論

    # re: CMS gc實踐總結  回復  更多評論   

    2009-09-22 11:42 by Scorpio Zhen
    不錯,更深入的學習gc方面的知識
    主站蜘蛛池模板: 99精品视频在线观看免费| 边摸边吃奶边做爽免费视频网站| 国产又黄又爽又大的免费视频 | 久别的草原电视剧免费观看| 国产精品V亚洲精品V日韩精品 | 亚洲男人av香蕉爽爽爽爽| 国产亚洲精彩视频| 国产中文字幕免费观看| 无套内谢孕妇毛片免费看看 | 日本特黄特色免费大片| 亚洲爆乳少妇无码激情| 狼友av永久网站免费观看| 亚洲国产精品美女久久久久| 日韩a级毛片免费观看| 免费无码一区二区| 在线亚洲人成电影网站色www| 免费毛片在线看不用播放器 | 亚洲av综合av一区二区三区| 免费国产不卡午夜福在线| 成人精品视频99在线观看免费| 亚洲成av人在线视| 91免费国产自产地址入| 亚洲爆乳成av人在线视菜奈实| 啦啦啦www免费视频| 女人裸身j部免费视频无遮挡| 亚洲无码在线播放| 免费观看无遮挡www的视频| 亚洲欧美黑人猛交群| 亚洲阿v天堂在线2017免费| 两性色午夜视频免费播放| 亚洲男人都懂得羞羞网站| 免费精品国产自产拍在| 青草久久精品亚洲综合专区| 亚洲一区爱区精品无码| 五月婷婷在线免费观看| 曰批全过程免费视频观看免费软件| 亚洲国产日韩一区高清在线| 日本免费高清一本视频| 午夜免费福利片观看| 亚洲av无码专区青青草原| 亚洲国产另类久久久精品|