2016-01-05 143 views
0

我正在爲一個大文件(〜30GB)實現一個外部排序,所以在我將這些塊寫入磁盤之後,我創建了chunksBufferedReader(new OutputStreamWriter(new FileOutputStream(outputPath), "UTF-8"), maxBufferSize)maxBufferSize = Runtime.getRuntime().freeMemory()/chunks。但是我得到一個OutOfMemory異常。JVM內存不足

我想垃圾回收器沒有足夠的時間來清理內存(當我停止調試器,它不會拋出異常),但在這種情況下,爲什麼Runtime.getRuntime().freeMemory()給出了這樣的結果?

是否可以顯式調用垃圾回收或唯一的選項是睡眠一段時間?

+0

可能重複的[我們可以明確調用垃圾收集器嗎?](http://stackoverflow.com/questions/15632734/can-we-call-the-garbage-collector-explicitly) –

+0

還要注意,freeMemory()告訴您堆中可用空間的總量,但不能保證有一個大的連續塊(​​事實上,通常情況並非如此)。 –

+0

知道你會得到什麼樣的'OutOfMemoryError'是很重要的 - 不知道我們可能會把你完全錯誤的發送給你。還有一些(相關的)代碼會很好.... –

回答

2

是否有可能顯式調用垃圾收集

是的,它是可能的。但它不會有任何好處。

執行完整的GC後,JVM只會拋出OOME。明確調用System.gc()將(很可能)只是浪費CPU時間。


事實上,我認爲你真正的問題是在這裏:

創建chunksBufferedReader(new OutputStreamWriter(new FileOutputStream(outputPath), "UTF-8"), maxBufferSize)maxBufferSize = Runtime.getRuntime().freeMemory()/chunks

當您考慮各種對象開銷時,(maxBufferSize + overheads) * chunks可能比可用內存量大一點。

一般來說,用Java堆接近完整運行是一個壞主意。即使你沒有完全用完空間,你也可以發現接近完整的運行會觸發很多(太多)垃圾收集。

在這種情況下,您真的從大型I/O緩衝區中獲益不大。緩衝區範圍從8KB到64KB應該沒問題......是我的直覺。另見Peter Lawrey的評論!

+0

大於32 KB的緩衝區可能會稍微慢一些。我懷疑這是由於L1 cpu緩存的大小造成的,但我發現它對於最佳尺寸有什麼不同。 –

0

您可以嘗試使用System.gc(),但它不是最有用的。你可以嘗試給程序更多的內存。