2015-12-10 61 views
4

我有,有很多記憶流失了大量堆分配的Clojure的應用程序運行,所以它適當地設置JVM選擇採用:JVM運行老根垃圾收集時,老根是「空」

-Xmx13g -XX:+UseConcMarkSweepGC -XX:NewSize=10G -server -XX:+UseParNewGC 

這在大多數情況下都是有效的,並且避免了新代碼溢出到舊代的問題(有時仍然會讓代碼生存下來,但並不總是),但有時我們會看到像JVM運行CMS /舊代碼垃圾收集新一代充滿時真的很難。但我的理解是,這應該由新一代垃圾收集器來處理。

enter image description here

兩個問題。爲什麼舊的垃圾收集器在老舊的幾乎是空的時候運行,但是新的舊的垃圾收集器呢?是否還有進一步的調整可以減少GC不可避免地造成的停頓/減速?

ETA:運行OpenJDK的8

ETA 2:GC日誌:https://gist.github.com/gworley3/6abb9ab52320c6cbd508

+3

我沒有看到舊空間是垃圾收集的跡象。 – AppX

+0

基於查看運行CMS的大量CPU時間(請參閱圖像中的垃圾回收CPU時間圖) –

+1

您應該啓用GC日誌併發布相當大的樣本。您還應該指定您正在使用的JVM版本。此外,你的新的gen大小似乎過度。 – the8472

回答

2

答案很簡單:

CMS花費太多的時間掃描近10GB的年輕創時它不有。您可以防止通過添加不必要的選項運行CMS收集:

‑XX:+UseCMSInitiatingOccupancyOnly ‑XX:CMSInitiatingOccupancyFraction=<K>

ķ被佔用的古根空間的任意部分。

龍答:

參考Oracle CMS Documentation

的CMS收集器併發收集週期暫停的應用程序的兩倍。第一個暫停是將從根可直接訪問的對象(例如,應用程序線程堆棧和寄存器,靜態對象等的對象引用)以及堆中其他地方(例如,年輕代的) 。這第一次暫停被稱爲初始標記暫停。第二次暫停是在併發跟蹤階段結束時發現的,並且在CMS收集器完成跟蹤該對象之後,由於對象中引用的應用程序線程的更新而找到由併發跟蹤所遺漏的對象。第二次暫停稱爲暫停。

CMS正在做兩個停止的世界暫停,每次掃描楊根的標記。查看日誌的前三行,可以看到ParNew之前5秒鐘,以及0.25秒之後。這句話看到了類似的時間減少。

<190>1 2015-12-18T08:44:54.194216+00:00 host app web.1 - [GC[YG occupancy: 489826 K (9437184 K)][Rescan (parallel) , 0.2520950 secs][weak refs processing, 0.0000180 secs][scrub string table, 0.0008190 secs] [1 CMS-remark: 64504K(107240K)] 554330K(9544424K), 0.2530410 secs] [Times: user=1.95 sys=0.02, real=0.25 secs] 

<190>1 2015-12-18T08:44:49.937257+00:00 host app web.1 - [GC[ParNew: 8418004K->93508K(9437184K), 0.0488580 secs] 8482343K->158013K(9544424K), 0.0489980 secs] [Times: user=0.33 sys=0.00, real=0.05 secs] 

<190>1 2015-12-18T08:44:48.651086+00:00 host app web.1 - [GC [1 CMS-initial-mark: 64339K(107240K)] 7800216K(9544424K), 5.0756660 secs] [Times: user=5.08 sys=0.00, real=5.08 secs] 

在每個CMS週期後,您的舊Gen空間幾乎不會減少,所以開銷肯定不值得。降低CMS週期的頻率將是一種可能的解決方案。

+0

這似乎解決了這個問題。將入住率設置爲70,效果很好。感謝您對cms工作方式的深入瞭解:我的印象是,像系列gc一樣,只有在舊有東西存在的情況下才會運行。 –