2010-04-30 83 views
6

我正在Linux 8位核心CPU和6 GB內存的Linux 64位上運行應用程序服務器。調整高響應服務器應用程序的JVM(GC)

服務器必須高度響應。

經過一番檢查後,我發現運行在服務器上的應用程序創建了相當數量的短暫對象,並且只有大約200〜400 MB的長壽命對象(只要沒有內存泄漏)

讀取http://java.sun.com/javase/technologies/hotspot/gc/gc_tuning_6.html 後我使用這些JVM選項

-server -Xms2g -Xmx2g -XX:MaxPermSize=256m -XX:NewRatio=1 -XX:+UseConcMarkSweepGC 

結果:次要GC取0.01〜0.02秒,主要的GC需要1〜3秒 次要GC不斷髮生。

我該如何進一步改進或調整JVM?

較大的堆大小?但GC需要更多時間嗎?

更大的NewSize和MaxNewSize(年輕一代)?

其他收藏家?平行GC?

是否讓主要GC更頻繁地發生是一個好主意?如何?

回答

7

結果可以看出:未成年GC需要0.01〜0.02秒,各大GC需要1〜3秒的未成年人GC不斷髮生。

除非你報告暫停,否則我會說CMS收集器正在做你要求它做的事情。根據定義,CMS將使用比串行和並行收集器更大比例的CPU。這是您爲低停頓時間支付的罰款。

如果你看到1到3秒暫停次,我想說你需要做一些調整。我不是專家,但它看起來應該從默認值92減少CMSInitiatingOccupancyFraction的值開始。

增加堆大小將提高GC的「吞吐量」。但是如果你的問題長時間停頓,增加堆的大小可能會使問題變得更糟。

2

您可能有興趣嘗試低停頓Garbage-First collector而不是併發標記掃描(儘管對於所有集合來說不一定更高性能,它應該有更好的最壞情況)。它由-XX:+UseG1GC啓用,應該是非常棒的,但在生產中使用它之前,您可能需要對其進行全面評估。它,因爲可能已經改善,但它似乎已經有點越野車在一年前,在Experience with JDK 1.6.x G1 (「Garbage First」)

+0

我會指出,Azul Zing jvm在許多情況下「更具性能」。他們在應用程序運行時在幕後執行gC。非常酷的東西。再一次,它不是免費的,但對於那些希望取消調整JVM的人來說,這可以做到。我認爲他們稱之爲他們的C4收集器(併發,連續,壓縮,收集器?)。 Mike McCandless最近基準測試了Apache Lucene/Solr對CMS的測試。可伸縮性的巨大成果:http://blog.mikemccandless.com/2012/07/lucene-index-in-ram-with-azuls-zing-jvm.html我一直在關注這個,因爲它改變了遊戲 – 2012-09-07 14:19:36

1

如果垃圾回收器與您的程序並行運行,如果您有足夠的CPU,則可以完成此任務。

你想要什麼,是要絕對確定你不會遇到垃圾收集暫停你的主程序的場景。

您是否嘗試過除了說明需要服務器虛擬機(用於Sun JVM)之外沒有任何標誌,然後將服務器置於沉重負載下以查看其行爲?只有這樣你才能看到,如果從修補選項中得到任何改進。

1

這實際上聽起來像是一個吞吐量應用程序,應該可能使用吞吐量收集器。我會平衡新生代的大小,使其足夠大,不會太頻繁地GC,並且足夠小以防止長時間停頓。 20ms對我來說聽起來像是一個很長的次要GC。我也懷疑你的倖存者空間太大,而且正在被浪費。如果你在老年人身上沒有太多的倖存者,那麼你應該沒有那麼多幸存你的小GC。

最後,您應該使用jvmstat和VisualGC來真正瞭解您的應用程序如何使用內存。

2

小心......如果您不謹慎,GC可能是一個多毛的問題。在任何運行時(JVM for Java/CLR for .Net)中,都有幾個進程發生。通常存在早期的記憶優化(年輕一代垃圾收集/年輕一代GC &舊代垃圾收集/老一代GC)。年輕的gen gc定期發生,並且通常歸因於您的較小暫停/打嗝。當你看到長時間「停止世界」停頓時,舊的gc通常會發生什麼。

爲什麼你會問?你的運行時/ JVM暫停的原因是,當運行時清理Heap時,它必須經歷所謂的相變。它會停止運行應用程序的線程,以便標記和交換指針以優化可用內存。永根更快,因爲它主要是釋放只是暫時的物體。然而,老一代對堆上的所有物體進行評估,當內存耗盡時,它會開始釋放所需的內存。

爲什麼要小心?老一代在暫停時間越來越糟,你使用的堆越多。在總堆大小爲2-4 GB時,在Java 6(JDK 1.6+)等現代運行時應該沒問題。一旦超越了這個閾值,你會看到暫停時間呈指數增長。我遇到了一些必須重新啓動服務器的客戶端,因爲在某些情況下堆很大,GC暫停時間可能比完全重新啓動時間要長。

有一些新的工具非常酷,可以給你評估GC是否是你的痛苦的領先優勢。 JHiccup是一個,它是免費的azulsystems網站。在這個時候,我認爲它只適用於Linux。他們也有一個JVM,它具有重新構建的GC算法,可以暫停運行...但是如果您使用的是非關鍵應用程序的單個服務器部署,那麼它可能不具有成本效益(這不是一個免費的)。總結 - 如果你的運行時/ JVM/CLR堆小於2 GB,增加更多的內存將有所幫助。一定要給自己一些開銷。如果可能的話,你永遠不會想要達到100%的堆大小/內存大小。那是長時間停頓最長的時候。給自己一個額外的20%以上的記憶,超出你認爲你需要的東西。這樣,您就有足夠的空間讓GC算法移動對象進行優化。如果你打算大規模......有一種工具可以修復大約1990年的JVM技術(Azul Systems Zing JVM),但它不是免費的。他們確實提供了一個開源工具來診斷GC問題。 JVM(我已經嘗試過了)也有一個非常酷的線程級可見性工具,可以讓你在沒有開銷的情況下報告生產中的任何泄漏,錯誤或鎖定(與JVM已經處理的數據卸載和時間戳有關的一些技巧)。這節省了大量的開發測試時間......但再次,不適用於小應用程序。

保持在4 GB以下。提供額外的空間。如果你願意,你可以打開這些標誌來監控的Java/JVM GC:

java -verbose:gc myProgram 
java -Xloggc:D:/log/myLogFile.log -XX:+PrintGCDetails myProgram 

您可以嘗試一些其他的收藏熱點使用的。有不止一個。

如果你在Linux上,繼續嘗試JHiccup工具。這是免費的。

1

對於高響應的服務器應用程序,我認爲您希望看到主要的GC發生頻率較低。這裏是參數列表將有所幫助。

-XX:+ CMSParallelRemarkEnabled
-XX:+ CMSScavengeBeforeRemark
-XX:+ UseCMSInitiatingOccupancyOnly
-XX:CMSInitiatingOccupancyFraction = 50
-XX:CMSWaitDuration = 300000
-XX:GCTimeRatio = 40

只要您的應用程序沒有耗盡內存,較大的堆大小可能無法幫助低停頓。

更大的NewSize和MaxNewSize將有助於吞吐量,可能無助於低停頓。如果您選擇採用此方法,則可以考慮通過將-XX:GCTimeRatio設置得更低來爲GC線程提供更多的執行時間。關鍵是要記住在調整JVM時採取整體性。

0

我認爲之前的海報錯過了一些非常明顯的東西 - 燙髮代碼太小。如果系統使用200到400 MB作爲永久生成 - 那麼最好將Max Perm Gen設置爲400 MB。 PerGen的大小也應該設置爲相同的值。您將永遠不會耗盡永久代空間。

目前看起來JVM需要花費大量時間將物體移入和移出永久代。這可能需要時間。 JVM嘗試爲Java對象分配連續的內存區域 - 這加速了由於硬件級別功能而導致的內存訪問。爲了做到這一點,在內存中有足夠的緩衝區是非常有幫助的。如果Permanent Generation幾乎已滿,則必須拆分新發現的永久對象,或者必須對現有對象進行洗牌。這是觸發完整GC的原因,也會導致長時間的完整GC暫停。

該問題指出永久代的大小已經被測量 - 如果尚未完成,則應使用工具測量。這些工具在啓用verboseGC選項的情況下處理由JVM生成的日誌。

以上列出的所有標記和掃描選項 - 可能不需要這個基本的改進。

人們將GC選項作爲解決方案而不評估它們在實際使用中證明了多麼成熟。

+0

我想你對永久一代感到困惑。它不包含對象,它包含類定義,類元數據等。 – 2015-12-08 12:40:05