☕【JVM性能調優】「CMS垃圾回收器」調優化方案

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"前提概要","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"如果沒有冬天,春天不會如此悅人;如果沒有偶爾的不幸,幸運不會如此受人歡迎","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"CMS垃圾回收的6個重要階段","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"numberedlist","attrs":{"start":1,"normalizeStart":1},"content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":1,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"initial-mark 初始標記(CMS的第一個STW階段),標記GC Root直接引用的對象,GC Root直接引用的對象不多,所以很快。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":2,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"concurrent-mark併發標記階段,由第一階段標記過的對象出發,所有可達的對象都在本階段標記","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":3,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"concurrent-preclean 併發預清理階段,也是一個併發執行的階段。在本階段,會查找前一階段執行過程中,[從新生代晉升或新分配或被更新的對象]。通過併發地重新掃描這些對象,預清理階段可以減少下一個stop-the-world 重新標記階段的工作量","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":4,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"concurrent-abortable-preclean","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":",","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"併發可中止的預清理階段。這個階段其實跟上一個階段做的東西一樣,也是爲了減少下一個STW重新標記階段的工作量。增加這一階段是爲了讓我們可以控制這個階段的結束時機,比如掃描多長時間(默認5秒)或者Eden區使用佔比達到期望比例(默認50%)就結束本階段","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":5,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"remark重標記階段(CMS的第二個STW階段),暫停所有用戶線程,從GC Root開始重新掃描整堆,標記存活的對象。需要注意的是,雖然CMS只回收老年代的垃圾對象,但是這個階段依然需要掃描新生代,因爲很多GC Root都在新生代,而這些GC Root指向的對象又在老年代,這稱爲“跨代引用”","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":6,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"concurrent-sweep ,併發清理","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"分析","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"分析其GC日誌,發現GC發生在CMS的收集階段","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/58/585f78f44df3c46d132091f927fe049a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"箭頭1 顯示abortable-preclean階段耗時4.04秒","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"箭頭2 顯示的是remark階段,耗時0.11秒","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"雖然abortable-preclean階段是concurrent的,不會暫停其他的用戶線程。就算不優化,可能影響也不大。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"調優之前先看下該應用的GC統計數據,包括GC次數,耗時:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/f0/f06a461548594dd1dc27583dada1d96f.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":" 統計期間內(18天)發生CMS GC 69次,其中abortable preclean階段平均耗時2.45秒,final remark階段平均112ms,最大耗時170ms。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"優化目標","attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"降低abortable preclean時間,而且不增加final remark的時間(因爲remark是STW的)。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"JVM參數調優","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"第一次調優","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"先嚐試調低","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"abortable preclean","attrs":{}}],"attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"階段的時間,看看效果。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"有兩個參數可以控制這個階段何時結束:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"-XX:CMSMaxAbortablePrecleanTime=5000\n","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong","attrs":{}}],"text":"默認值5s,代表該階段最大的持續時間","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"-XX:CMSScheduleRemarkEdenPenetration=50","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"默認值50%,代表Eden區使用比例超過50%就結束該階段進入remark","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"調整爲最大持續時間爲1s,Eden區使用佔比10%","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":",如下:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"-XX:CMSMaxAbortablePrecleanTime=1000\n-XX:CMSScheduleRemarkEdenPenetration=10","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"爲什麼調整成這樣兩個值:首先每次CMS都發生在老年代使用佔比達到80%時,因爲這是由下面兩個參數決定的","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":":","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"-XX:CMSInitiatingOccupancyFraction=80\n-XX:+UseCMSInitiatingOccupancyOnly","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"這兩個設置一般配合使用,一般用於『降低CMS GC頻率或者增加頻率、減少GC時長』的需求","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"-XX:CMSInitiatingOccupancyFraction=80 ","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"是指設定CMS在對內存佔用率達到80%的時候開始GC(因爲CMS會有浮動垃圾,所以一般都較早啓動GC)","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":";","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"-XX:+UseCMSInitiatingOccupancyOnly","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":" :","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"標誌來命令JVM不基於運行時收集的數據來啓動CMS垃圾收集週期","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":" 當該標誌被開啓時,JVM通過CMSInitiatingOccupancyFraction的值進行每一次CMS收集,而不僅僅是第一次。(否則後續會動態控制回收閾值)","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":" (慎用) 因此,只有當我們充足的理由(比如測試)並且對應用程序產生的對象的生命週期有深刻的認知時,才應該使用該標誌。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"老年代的增長是由於部分對象在","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"Minor GC","attrs":{}}],"attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"後仍然存活,被晉升到老年代,導致老年代使用佔比增長的","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":",也就是在每次","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"CMS GC","attrs":{}}],"attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"發生之前剛剛發生過一次","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"Minor GC","attrs":{}}],"attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":",","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"所以在那一刻新生代的使用佔比是很低的","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":" 那麼我們預計這個時候儘快結束abortable preclean階段,在remark時就不需要掃描太多的Eden區對象,remark STW的時間也就不會太長","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"第一次調整參數","attrs":{}}]},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/08/08e7b04e2deacf68dce0096d779e4744.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":" 在統計期間(17小時左右)內,發生過2次CMS GC。Abortable Preclean 平均耗時835ms,這是預期內的。但是Final Remark 平均耗時495ms(調整前是112ms),其中一次是80ms,另一次是910ms!將近1秒鐘!Remark是STW的!對於要求低延時的應用來說這是無法接受的!","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/4a/4a85e83b32525153416696c019ed825d.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"[YG occupancy: 181274 K (1887488 K)] - 年輕代當前佔用情況和總容量","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"耗時80ms的這次remark發生時(早上9點,非高峯時段),新生代(YG)佔用181.274M。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"remark耗時910ms的那次GC日誌","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"[YG occupancy: 773427 K (1887488 K)]","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"耗時910ms的這次remark發生時(晚上10點左右,高峯時段),新生代(YG)佔用773.427M。因爲這個時候高峯期,新生代的佔用量上升的非常快,幾乎同樣的時間內,非高峯時段僅上升到181M,但是高峯時段就上升到773M。","attrs":{}}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"如果","attrs":{}},{"type":"codeinline","content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"abortale preclean","attrs":{}}],"attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"階段時間太短,隨後在remark時,新生代佔用越大,則remark持續的時間(STW)越長","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"不縮短abortale preclean耗時會出現過程gc;縮短的話,remark階段又會變長,而且是STW,更不能接受。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"對於這種情況,CMS提供了CMSScavengeBeforeRemark參數,嘗試在remark階段之前進行一次Minor GC,以降低新生代的佔用","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"第二次調優","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":" 增加 ","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"-XX:+CMSScavengeBeforeRemark","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":" 不是沒有代價的,因爲這會增加一次Minor GC停頓。所以這個方案好或者不好的判斷標準就是:","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"增加CMSScavengeBeforeRemark參數之後的minor GC停頓時間 + remark 停頓時間如果比增加之前的remark GC停頓時間要小,這纔是好的方案。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":" -XX:+CMSScavengeBeforeRemark: 在CMS GC前啓動一次ygc,目的在於減少old gen對ygc gen的引用,降低remark時的開銷-----一般CMS的GC耗時 80%都在remark階段","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"第二次調整的結果","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":" 在統計期間(20小時左右)內,發生3次CMS GC。Abortable preclean 平均耗時693ms。Final remark平均耗時50ms,最大耗時60ms。Final remark的時間比調優前的平均時間(112ms)更低","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/e3/e39d92b504b4e4751264988559a1d77a.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"3次CMS GC remark前的Minor GC日誌分析","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"第1次是非高峯時段的表現,Minor GC 耗時 0.01s + remark耗時 0.06s = 0.07s = 70ms,如下","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/bc/bc46f0757e82f1a2677422d55920e8e3.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"第2次是高峯時段,Minor GC 耗時 0.01s + remark耗時 0.05s = 0.06s = 60ms,如下","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/1d/1d2385cf63d8a2f401a750c12e04279e.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"第3次是非高峯時段,Minor GC 耗時 0.00s + remark耗時 0.04s = 0.04s = 40ms,如下","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https://static001.geekbang.org/infoq/ab/ab6b54087d417a089c210191406cab36.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"所以,3次Minor GC + remark耗時的平均耗時 < 60ms,這比第一次調優時remark平均耗時495ms好得多了","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}],"attrs":{}},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"總結","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"解決abortable preclean 時間過長的方案可以歸結爲兩步:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"縮短abortable preclean 時長,通過調整這兩個參數:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"text"},"content":[{"type":"text","text":"-XX:CMSMaxAbortablePrecleanTime=xxx\n-XX:CMSScheduleRemarkEdenPenetration=xxx","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"調整爲多少的一個判斷標準是:abortable preclean階段結束時,新生代的空間佔用不能大於某個參考值。 在前面第一次調優後,新生代(YG)佔用181.274M,remark耗時80ms;新生代(YG)佔用773.427M時,remark耗時910ms。所以這個參考值可以是300M。","attrs":{}}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":"而如果新生代增長過快,像這次調優應用2秒內就能用光2G新生代堆空間的,就只能通過CMSScavengeBeforeRemark做一次Minor GC了","attrs":{}},{"type":"text","marks":[{"type":"size","attrs":{"size":10}}],"text":"。","attrs":{}}]}]}],"attrs":{}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":" 增加CMSScavengeBeforeRemark參數開啓remark前進行Minor GC的嘗試","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"size","attrs":{"size":10}},{"type":"strong","attrs":{}}],"text":" 雖然官方說明這個增加這個參數是嘗試進行Minor GC,不一定會進行。但實際使用起來,幾乎每次remark前都會Minor GC。","attrs":{}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章