2016-01-05 144 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(),但它不是最有用的。你可以尝试给程序更多的内存。