2016-10-12 52 views
0

我得到了GC開銷超過限制,但記憶中留下

java.lang.OutOfMemoryError: GC overhead limit exceeded 

而分裂一些字符串。有趣的是,內存都沒有用完,垃圾收集器也沒有變得瘋狂:JVisualVM output

例外發生在11:10,當Eclipse在實際拋出異常之前凍結了程序。所以11:10之後的一切都可能只是噪音。

我多次遇到這個問題,在我的長期運行的程序,但我不知道如何避免它。即使分配更多的內存也只會延遲但不會阻止它。

+0

您是否嘗試過與運行'-XX:+ HeapDumpOnOutOfMemoryError'然後檢查的轉儲? – Axel

+0

我有一個轉儲,但實際上我不知道要搜索什麼。 –

+0

嗯......例如,對於一個你不期望的類的異常大量的對象實例。但是你還可以做其他事情:在OutOfMemoryError上放置一個Exception。現在,當OOM發生時,不僅有相關的堆棧跟蹤,而且實際上可以使用調試器在發生故障時檢查輸入參數等。 – Axel

回答

2

您使用停止的世界GC(可能是並行清除)。這例外是因爲GC需要太多的時間,總運行時間這可能超過98%。在這種情況下,JVM殺死進程,因爲沒有真正的工作正在完成。

的解決方案可能是:

  1. 嘗試另一種類型的GC,如併發標記掃描,這是不會停止的環球GC;
  2. 嘗試更大的內存,所以GC不那麼頻繁;
  3. 忽略此GC時間限制,使用-XX:-UseGCOverheadLimit,這可能會導致問題,因爲JVM一直在GC上工作,而不是真正的工作;
  4. 如上所述,轉儲內存跟蹤-XX:+HeapDumpOnOutOfMemoryError並分析跟蹤。

多一點的解釋,爲什麼堆未滿,但GC超限(所有這些都是猜測,而需要更多的走線,以確保產生的原因): 這可能是

  1. 太小年輕一代或大多數物體從較小的GC中存活,所以GC發生得太頻繁和/或花費很長時間移動物體(這可以通過改變堆上年輕代的大小,或通過一些JVM標記改變物體的佔有率來調整)。
  2. 過小的舊世代大小使得從小GC中存活的物體不能適應老一代,這導致頻繁的主GC(或全堆GC)。
相關問題