使用 Java 映射大于 2GB 的文件

Posted

技术标签:

【中文标题】使用 Java 映射大于 2GB 的文件【英文标题】:Mapping files bigger than 2GB with Java 【发布时间】:2011-07-02 07:57:20 【问题描述】:

一般可以这么说:你如何在Java中为大于2GB的内存映射文件实现byte[] get(offset, length)方法。

有上下文:

我正在尝试使用随机 i/o 有效读取大于 2GB 的文件。当然这个想法是使用 Java nio 和内存映射 API。

问题在于内存映射的限制为 2GB。一种解决方案是映射多个 2GB 的页面并通过偏移量进行索引。

这里有一个类似的解决方案:

Binary search in a sorted (memory-mapped ?) file in Java

这个解决方案的问题是它被设计为读取字节,而我的 API 应该读取 byte[](所以我的 API 类似于 read(offset, length))。

将最终的get() 更改为get(offset, length) 会起作用吗?当我正在阅读的byte[] 位于两页之间时会发生什么?

【问题讨论】:

【参考方案1】:

不,我对Binary search in a sorted (memory-mapped ?) 的回答无法将get() 更改为get(offset, length),因为内存映射文件数组边界,就像你怀疑的那样。我可以看到两种可能的解决方案:

    重叠内存映射文件。当您进行读取时,选择内存映射文件,其起始字节紧接在读取的起始字节之前。这种方法不适用于大于最大内存映射大小 50% 的读取。 创建从两个不同的两个不同内存映射文件读取的字节数组创建方法。我不喜欢这种方法,因为我认为一些性能提升会丢失,因为生成的数组不会内存映射。

【讨论】:

会失去哪些性能提升?如果您返回byte[],则无论如何您都是从mmap()ed 区域复制的。在相同的总字节数上调用 System.arraycopy 两次而不是一次并没有那么糟糕。 @Scott Lamb:我同意当get() 需要从“二分搜索”算法中的两个不同映射中读取时,对于那些可能很少见的边缘条件,性能损失可以忽略不计。我的回答是说你需要围绕它编写代码,因此有两个选项。仅在get() 后面添加没有新代码的偏移量将导致诸如索引越界错误之类的硬错误。

以上是关于使用 Java 映射大于 2GB 的文件的主要内容,如果未能解决你的问题,请参考以下文章

Android进程内存映射

主存与Cache间组相联映射计算

System.IO.File.ReadAllBytes 用于大于 2GB 的文件

mybatis映射文件Xml比较大小写法

Java NIO MappedByteBuffer OutOfMemoryException

oracle 中的啥数据类型会映射到 Java int?