2010-08-11 75 views
9

我們最近開始偶爾使用有關「java.lang.OutOfMemoryError:請求8589934608字節的Chunk :: new。Out of swap space?」消息開始崩潰的應用程序。Java JIT編譯器導致OutOfMemoryError

我環顧四周,在網絡上,到處都建議只限於

  • 恢復到以前的版本的Java
  • 小提琴與內存設置
  • 使用客戶端而不是服務器模式

恢復到以前的版本意味着新的Java有一個錯誤,但我沒有看到任何跡象。記憶根本不是問題;服務器有32GB可用,並且Xmx設置爲20,而Xms是10.我看不到剩餘12GB的JVM耗盡(減少給予機器上其他幾個進程的量)。由於應用程序和環境的特性,我們堅持使用服務器模式。

當我查看應用程序的內存和CPU使用情況時,我發現整天的內存使用量不斷增加,但在使用之前突然發生CPU使用率高達100%,內存使用量從X增加到X + 2GB,到X + 4GB,到(有時)X + 8GB,到JVM死亡。這似乎是在JIT編譯中可能發生循環重複數組大小調整。

我現在看到上述8GB請求和16GB請求發生錯誤。所有時候,這種情況發生時編譯的方法都是一樣的。這是一個簡單的方法,它具有非嵌套循環,沒有遞歸,並且使用方法直接返回靜態成員字段或實例成員字段,計算量很少。

所以我有2個問題:

  1. 沒有任何人有什麼建議嗎?
  2. 我可以測試在測試環境中是否存在編譯此特定方法的問題,而不運行整個應用程序,直接調用JIT編譯器?或者我應該啓動應用程序,並告訴它編譯方法後小得多的調用計數(如2),迫使它編譯方法幾乎立即而不是在一天的隨機點?

@StephenC

JVM是1.6.0_20(先前1.6.0_0),在Solaris運行。我知道這是由於幾個原因導致問題的彙編。

  1. 在導致它的秒ps示出與對應於編譯器線程(從jstack)ID的Java線程佔用了100%的CPU時間
  2. jstack示出了問題是JavaThread "CompilerThread1" daemon [_thread_in_native, id=34, ...]

jstack中提到的方法總是一樣的,而且是我們寫的。如果您看到示例jstack輸出,您將知道我的意思,但出於顯而易見的原因,我無法提供代碼示例或文件名。我會說這是一個非常簡單的方法。 Essentiall少數空檢查,2 for循環進行平等檢查並可能分配值,以及一些簡單的方法調用之後。總共可能有40行代碼。

儘管應用程序每天運行並且每天都重新啓動,但該問題在兩週內發生過兩次。此外,這些應用程序在這些時間都沒有承受重負。

+0

如果您說出您正在使用的JVM版本和補丁級別(以及之前的內容)以及您的操作系統/硬件平臺是什麼,這將會很有幫助。另外,爲什麼你在JIT編譯期間得出結論:問題是如何發生的,你如何計算出正在編譯的方法......以及方法的代碼是什麼樣的。 – 2010-08-11 08:59:28

+0

您是否找到滿意的解決方案? – 2015-01-01 17:48:00

+0

對不起*非常*遲到的回覆 - 我已經標記了答案 – Phil 2015-03-15 12:06:03

回答

1

好吧,我做了一個快速搜索,發現了一個關於sun java的線程forums that discusses這個。希望能幫助到你。

+0

是的,我也看到了。他的問題是與單個分配中剩餘的記憶相沖突。我看到多個數組resizings不應該有的地方。編譯一個方法沒有理由需要16GB的內存,對吧? – Phil 2010-08-11 05:31:44

+0

然後,你也可能嘗試了你在你的問題中提到的建議。這些工作是否有用? – naikus 2010-08-11 06:09:34

1

這裏另一個entry on Oracles forum。類似零星的崩潰。有一個答案,通過重新配置gc的倖存者比率來解決問題。

5

通過創建名爲.hotspot_compiler的文件並將其放入應用程序的工作目錄中,可以排除特定的方法被JIT處理。只需按以下格式在文件中添加一個條目:

exclude com/amir/SomeClass someMethod 

而且從編譯器的控制檯輸出將類似於:

### Excluding compile: com.amir.SomeClasst::someMethod 

欲瞭解更多信息,請閱讀this。如果你不知道你的應用程序「工作目錄」,在您的Java啓動腳本或命令行使用

-XX:CompileCommandFile=/my/excludefile/location/.hotspot_compiler 

。或者,如果您不確定它的JIT編譯器是否有錯誤,並且希望查看是否可以在沒有任何JIT的情況下重現此問題,請使用-Xint運行Java進程。