2010-05-19 167 views
9

有時,在每兩天一次到每兩週一次之間的某個地方,我的應用程序崩潰在代碼中看似隨機的位置:java.lang.OutOfMemoryError: GC overhead limit exceeded。如果我谷歌這個錯誤我來this SO question並導致我this piece of sun documentation其中expains:「java.lang.OutOfMemoryError:超出GC開銷限制」中的過長GC時間的持續時間

The parallel collector will throw an OutOfMemoryError if too much time is being spent in garbage collection: if more than 98% of the total time is spent in garbage collection and less than 2% of the heap is recovered, an OutOfMemoryError will be thrown. This feature is designed to prevent applications from running for an extended period of time while making little or no progress because the heap is too small. If necessary, this feature can be disabled by adding the option -XX:-UseGCOverheadLimit to the command line.

,告訴我,我的應用程序顯然是花費的總時間的98%,垃圾回收只收回2%的堆。

但什麼時候98%?應用程序運行整個兩週內的98%?最後一毫秒的98%?

我試圖確定一個最佳的方法來實際解決這一問題,而不是僅僅使用-XX:-UseGCOverheadLimit,但我覺得有必要更好地理解我解決這個問題。

+3

從文檔看,它似乎是整個2周的98%。您是否使用以下標誌啓用GC日誌:-verbose:gc -XX:+ PrintGCDetails XX:+ PrintGCTimeStamps -Xloggc:PATH_FROM_ROOT/gclog.log。很高興看到應用程序運行時間和由於GC而停止的時間。 – JoseK 2010-05-19 12:28:17

+0

GC日誌記錄是一個很好的建議,我會嘗試。 2周的98%似乎不太可能,但你說得對,這是文檔所暗示的。我希望這只是不準確寫作 – 2010-05-20 10:19:06

+0

你有沒有發現98%的時間意義?我的觀點是GC應該在異常發生的時刻佔用98%的應用程序利用率,而不是在2周內。 – 2010-08-25 10:01:52

回答

6

I'm trying to determine a best approach to actually solving this issue rather than just using -XX:-UseGCOverheadLimit but I feel a need to better understand the issue I'm solving.

嘛,你使用了太多的內存 - 和它的聲音,這是因爲一個緩慢的內存泄漏的可能。

你可以嘗試增加堆大小-Xmx,這將有助於如果這不是內存泄漏,而是一個跡象表明你的應用程序實際上需要很多堆,並且你現有的設置略低。如果這是內存泄漏,這隻會推遲不可避免的。

要調查它是否是內存泄漏,請指示VM使用-XX:+HeapDumpOnOutOfMemoryError開關在OOM上轉儲堆,然後分析堆轉儲以查看是否有比應該存在的某種更多的對象。 http://blogs.oracle.com/alanb/entry/heap_dumps_are_back_with是一個很好的開始。


編輯:由於命運的安排吧,我正好碰到這個問題,我自己就在此前一天,這一問題被問,在一個批處理風格的應用程序。這不是由內存泄漏引起的,增加堆大小也沒有幫助。我所做的實際上是減少堆大小(從1GB到256MB),使整個GC更快(儘管更頻繁)。 YMMV,但它值得一試。

編輯2:並非所有問題都通過較小的堆解決......下一步是使G1 garbage collector似乎比CMS做得更好。

+0

我正在嘗試一些分析,我也會嘗試一下。謝謝。 – 2010-05-20 10:23:11

+0

我走了一條和你一樣的路線,試驗參數。最終,增加堆大小和我的代碼的一些調整(雖然我沒有發現內存泄漏)似乎解決了我的問題。 – 2010-09-06 13:22:29

+0

爲什麼要在批量式應用程序中使用CMS或G1?吞吐量收集器是否更好? – endless 2013-03-12 03:07:42

1

的> 98%的人會在其中的存儲器小於2%被回收同期進行測量。

這很可能是有這個沒有固定的時間。例如,如果OOM檢查將在每隔1,000,000個對象進行實時檢查後完成。所花費的時間將取決於機器。

你很可能無法通過增加-XX:-UseGCOverheadLimit「解決」你的問題。最有可能的結果是,你的應用程序將慢如蝸牛,使用更多的內存,然後打在GC根本不恢復任何存儲了點。相反,修復你的內存泄漏,然後(如果仍然需要)增加你的堆大小。

1

But 98% of what time? 98% of the entire two weeks the application has been running? 98% of the last millisecond?

簡單的答案是它沒有指定。然而,在實踐中啓發式的「作品」,因此它不能是你所說的兩種極端解釋之一。

如果你確實想找出測量的時間間隔,你可以隨時閱讀OpenJDK 6或7的源代碼。但我不打擾,因爲它不會幫助你解決你的問題。

「最佳」方法是在調整過程中進行一些閱讀(從Oracle/Sun頁面開始),然後小心地「旋轉調諧旋鈕」。這不是非常科學,但考慮到當前可用的工具,問題空間(準確地說預測應用程序+ GC性能)「太難」了。

相關問題