Java NIO MappedByteBuffer OutOfMemoryException

我真的遇到了麻烦:我想使用FileChannelMappedByteBuffer读取几GB的HUGE文件 – 我发现的所有文档都暗示使用FileChannel.map()方法映射文件相当简单。 当然,限制在2GB,因为所有Buffer方法都使用int来定位,限制和容量 – 但系统隐含的限制如何呢?

实际上,我遇到了很多关于OutOfMemoryException的问题! 并没有真正定义限制的文档! 那么 – 如何将一个适合int-limit的文件安全地映射到一个或多个MappedByteBuffer而不仅仅是获得exception?

在尝试FileChannel.map()之前,我可以问系统我可以安全地映射文件的哪个部分? 怎么样? 为什么关于这个function的文档很少?

文件越大,你想要的内存就越少。 设计一种方法,一次处理一个缓冲区,一次一行,等等。

MappedByteBuffers特别有问题,因为没有定义的映射内存释放,因此一次使用多个基本上必然会失败。

我可以提供一些工作代码。 这是否能解决您的问题很难说。 通过文件搜索Hunter识别的模式。

请参阅优秀的文章Java技巧:如何快速阅读原始研究的文件 (不是我的)。

 // 4k buffer size. static final int SIZE = 4 * 1024; static byte[] buffer = new byte[SIZE]; // Fastest because a FileInputStream has an associated channel. private static void ScanDataFile(Hunter p, FileInputStream f) throws FileNotFoundException, IOException { // Use a mapped and buffered stream for best speed. // See: http://nadeausoftware.com/articles/2008/02/java_tip_how_read_files_quickly FileChannel ch = f.getChannel(); long red = 0L; do { long read = Math.min(Integer.MAX_VALUE, ch.size() - red); MappedByteBuffer mb = ch.map(FileChannel.MapMode.READ_ONLY, red, read); int nGet; while (mb.hasRemaining() && p.ok()) { nGet = Math.min(mb.remaining(), SIZE); mb.get(buffer, 0, nGet); for (int i = 0; i < nGet && p.ok(); i++) { p.check(buffer[i]); } } red += read; } while (red < ch.size() && p.ok()); // Finish off. p.close(); ch.close(); f.close(); } 

我使用的是List ,其中每个ByteBuffer映射到16 MB到1 GB的块中的文件。 我使用2的幂来简化逻辑。 我用它来映射最高8 TB的文件。

内存映射文件的一个关键限制是您受虚拟内存的限制。 如果你有一个32位的JVM,你将无法进行非常多的映射。

我不会继续为文件创建新的内存映射,因为它们永远不会被清除。 你可以创建很多这些,但在某些系统上似乎有大约32K的限制(无论它们有多小)

我发现MemoryMappedFiles有用的主要原因是它们不需要刷新(如果你可以假设操作系统不会死)这允许你以低延迟的方式写入数据,而不必担心如果丢失过多的数据应用程序因write()或flush()而死或性能过高。

您不使用FileChannel API一次写入整个文件。 相反,您将部分发送文件。 请参阅Martin Thompson的post中的示例代码,比较Java IO技术的性能 : Java顺序IO性能

此外,由于您正在进行与平台相关的调用,因此没有太多文档。 来自map() JavaDoc:

内存映射文件的许多细节本质上依赖于底层操作系统,因此未指定。