2013-04-18 39 views
2

我最近一直在性能上遇到困難,我的tomcat上運行的Java webapp將暫時掛起,導致流量積壓,導致Web應用程序暫時不可用,我懷疑這個時間與分鐘有關垃圾收集。Java垃圾回收和年輕代大小

我是垃圾收集小白,所以需要一點幫助。

我已經啓用了併發標記掃描垃圾收集器,希望這將消除暫停,但我還沒有發現,如果這已經解決了問題呢。

我還同時啓用了詳細的GC日誌記錄。

當前Java選項如下

-XX:MaxPermSize=128m -XX:+CMSClassUnloadingEnabled -XX:+UseConcMarkSweepGC -Xms4g -Xmx4g -Xss256k -verbose:gc -XX:+PrintGCDetails 

我從檢查GC輸出了年輕一代的空間是相當低的,在243MB注意到,並且正在迅速耗盡,而檢查一段的輸出我在10秒內計算了23個年輕一代的收藏。

與此同時,總堆消耗量穩步上升,達到最大值,接着是完整的垃圾收集,從大約3.5gb降至260mb,然後該模式再次重複其自身。

一個完整的GC

[GC [ParNew: 232750K->12960K(249216K), 0.0160890 secs] 3836696K->3616934K(4166656K), 0.0162110 secs] [Times: user=0.12 sys=0.01, real=0.02 secs] 
[GC [ParNew: 234528K->11391K(249216K), 0.0127970 secs] 3838502K->3615402K(4166656K), 0.0129370 secs] [Times: user=0.12 sys=0.00, real=0.01 secs] 
[GC [ParNew: 232959K->10253K(249216K), 0.0097850 secs] 3836970K->3614841K(4166656K), 0.0098850 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 
[GC [1 CMS-initial-mark: 3604588K(3917440K)] 3615964K(4166656K), 0.0096810 secs] [Times: user=0.01 sys=0.00, real=0.01 secs] 
[CMS-concurrent-mark: 0.196/0.196 secs] [Times: user=1.44 sys=0.03, real=0.20 secs] 
[CMS-concurrent-preclean: 0.013/0.014 secs] [Times: user=0.04 sys=0.00, real=0.01 secs] 
[GC [ParNew: 231821K->6718K(249216K), 0.0090430 secs] 3836409K->3611789K(4166656K), 0.0091460 secs] [Times: user=0.08 sys=0.01, real=0.01 secs] 
[CMS-concurrent-abortable-preclean: 0.176/0.390 secs] [Times: user=0.97 sys=0.04, real=0.39 secs] 
[GC[YG occupancy: 124723 K (249216 K)][Rescan (parallel) , 0.0698120 secs][weak refs processing, 0.0038070 secs][class unloading, 0.0170180 secs][scrub symbol & string tables, 0.0098050 secs] [1 CMS-remark: 3605071K(3917440K)] 3729794K(4166656K), 0.1070920 secs] [Times: user=0.78 sys=0.02, real=0.11 secs] 
[GC [ParNew: 228286K->6428K(249216K), 0.0079910 secs] 3755282K->3534155K(4166656K), 0.0080720 secs] [Times: user=0.07 sys=0.00, real=0.01 secs] 
[GC [ParNew: 227996K->6880K(249216K), 0.0085010 secs] 3332282K->3111216K(4166656K), 0.0085990 secs] [Times: user=0.08 sys=0.00, real=0.01 secs] 
[GC [ParNew: 228448K->12440K(249216K), 0.0108230 secs] 2721177K->2505200K(4166656K), 0.0109290 secs] [Times: user=0.13 sys=0.00, real=0.01 secs] 
[GC [ParNew: 234008K->8251K(249216K), 0.0073110 secs] 2358432K->2132792K(4166656K), 0.0074120 secs] [Times: user=0.07 sys=0.00, real=0.00 secs] 
[GC [ParNew: 229819K->5170K(249216K), 0.0071920 secs] 2056138K->1831867K(4166656K), 0.0072880 secs] [Times: user=0.07 sys=0.01, real=0.01 secs] 
[GC [ParNew: 226738K->11119K(249216K), 0.0106230 secs] 1589903K->1374447K(4166656K), 0.0107180 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 
[GC [ParNew: 232687K->8624K(249216K), 0.0078450 secs] 1273082K->1049051K(4166656K), 0.0079440 secs] [Times: user=0.09 sys=0.00, real=0.01 secs] 
[GC [ParNew: 230192K->10130K(249216K), 0.0083440 secs] 733461K->513411K(4166656K), 0.0084420 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 
[GC [ParNew: 231698K->10655K(249216K), 0.0092440 secs] 544833K->323816K(4166656K), 0.0093450 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 
[CMS-concurrent-sweep: 4.481/4.569 secs] [Times: user=13.24 sys=0.49, real=4.57 secs] 
[CMS-concurrent-reset: 0.008/0.008 secs] [Times: user=0.02 sys=0.00, real=0.01 secs] 
[GC [ParNew: 232223K->9791K(249216K), 0.0095050 secs] 495665K->273758K(4166656K), 0.0096020 secs] [Times: user=0.11 sys=0.00, real=0.01 secs] 
[GC [ParNew: 231359K->7434K(249216K), 0.0080890 secs] 495326K->271660K(4166656K), 0.0082230 secs] [Times: user=0.09 sys=0.00, real=0.01 secs] 
[GC [ParNew: 229002K->5732K(249216K), 0.0053690 secs] 493228K->269993K(4166656K), 0.0054630 secs] [Times: user=0.06 sys=0.00, real=0.01 secs] 
[GC [ParNew: 227300K->4017K(249216K), 0.0060080 secs] 491561K->268433K(4166656K), 0.0061010 secs] [Times: user=0.07 sys=0.00, real=0.00 secs] 

輸出示例我想知道,如果這個模式似乎正常的,我能做些什麼來優化和改善thisC。

我已閱讀關於增加年輕一代的大小,但不太熟悉垃圾收集我不知道這是否是正確的方法。

回答

2

這確實看起來像你的年輕一代的規模太小 - 頻繁收藏並不是真正的問題(這只是意味着你有一個內存密集型程序),但它有問題,你有很多內存被提升到下一代。幾件事情:

  1. 您是否有任何資源可以共享您可以使用ThreadPoolExecutor而不是創建新的Thread對象,還是可以共享數據庫連接?這會減慢你的內存消耗 - 混合資源將保留在你的成熟空間中,你不必將它們重新分配到你的年輕領域。

  2. 如果這不是一個選項,或者如果這不能減少你的成熟空間消耗,那麼增加你的年輕一代的規模。這樣做的目的不是爲了減少年輕一代的收藏數量(如果你將年輕一代的身高翻倍,那麼你會減少收藏數量,但每個收藏可能花費兩倍的**,所以你沒有得到任何東西) ,而這樣做的目的是爲了讓更多的時間讓你的年輕物體超出範圍,以便它們不被提升到成熟的空間。你想要做的比較是完整收藏的頻率 - 如果在增加年輕一代的尺寸之後你的收藏數量較少,那麼你已經成功了,否則將你的年輕一代減少到默認的尺寸。

**這是不完全正確的,因爲年輕一代收集器是複製收集器 - 它會將活動對象以成熟的空間,然後清除年輕空間。這意味着收集器的運行時間與活動對象的數量成正比,與時間成正比(與標記掃描集合的情況相同)。理想情況下,通過增加年輕一代的體積,您可以減少活物的數量,加快收集時間,並減少成熟的空間消耗。

+0

顯而易見的東西已經混合在一起,所以沒有運氣。我增加了年輕一代的規模,它像你所建議的那樣工作。大大減少次要收集的次數,但每次花費的時間實際上並沒有增加。全部收藏之間的時間現在也長得多。 – 3urdoch

+0

@murdoch你可以在http://blog.ragozin.info/2011/06/understanding-gc-pauses-in-jvm-hotspots.html找到GC暫停的粗略模型 –