3

我正在处理大文件,并且正在使用 MappedByteBuffer 进行读写操作。我有点缺乏知识,所以我想知道一些事情。

MappedByteBuffer buf = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, offset, size);

  1. 我知道 ByteBuffer 的大小限制是 Integer.MAX_VALUE 那么我应该如何设置 MappedByteBuffer 的大小?我应该使用小块还是 Integer.MAX_VALUE?

    那么如果我增加我的映射大小,我的应用程序读写性能也会提高吗?

  2. 当这个大小增加时,我的内存使用量是否也在增加?我想知道这是因为我正在创建多个文件来读写。所以也许如果一个文件分配 2gb 的内存,如果我有 6 个文件,我需要 12gb 的内存,或者我的想法完全错误。

  3. 它与 JVM -Xmx 或我的物理内存有关吗?

这是我的用法:

    List<MappedByteBuffer> mappings = new ArrayList<MappedByteBuffer>();
    
    int mSize = 25;
    
    long MAPPING_SIZE = 1 << mSize;
    
    File file = File.createTempFile("test", ".dat");
    RandomAccessFile raf = new RandomAccessFile(file, "rw");
    ByteOrder byteOrder = java.nio.ByteOrder.nativeOrder(); // "LITTLE_ENDIAN";
    
    try {
        long size = 8L * width * height;          
        for (long offset = 0; offset < size; offset += MAPPING_SIZE) {
            long size2 = Math.min(size - offset, MAPPING_SIZE);
            MappedByteBuffer buf = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, offset, size2);
            buf.order(byteOrder);
            mappings.add(buf);
        }
    }
4

2 回答 2

3
  1. 简短的回答是的,如果您知道您的文件将比 2g 大很多。唯一的缺点是您的磁盘空间使用量:如果您使用较大的增量,那么浪费的磁盘空间量将会更大,如果size不是MAPPING_SIZE.

  2. 只有您的虚拟内存使用量在增加。除非您使用的是 32 位机器,否则这应该不是问题。Linux 上的最大虚拟内存为 128TiB,因此您还有一些空间。如果您需要比这更多的虚拟内存,则需要寻求另一种解决方案。内存映射文件使用页面缓存:操作系统只会在使用时将文件页面 [1] 逐页加载到物理内存中,并在可用物理 RAM 紧张时卸载这些页面。

  3. 没有。见 2。

对于一些额外的资源,这里是页面缓存如何工作的一个很好的总结:页面缓存,内存和文件之间的事件

[1]:一个页面是一个OS级别的内存单元,一般为4KiB

于 2019-09-20T09:32:28.880 回答
1

关于第二点你是对的。第三点,它与你的物理记忆有关。首先,它取决于您的用例,但如果您采用 Integer.MAX_VALUE,您会在应用程序中看到一些滞后。

使用 MappedByteBuffer,我们需要确保文件适合内存。否则,我们可能会填满整个内存,结果会遇到常见的 OutOfMemoryException。我们可以通过只加载文件的一部分来克服这个问题。

MappedByteBuffer 创建与 JVM 内存的虚拟内存映射。文件内容加载到虚拟内存而不是堆中。

这里有几个链接可以帮助您更好地理解。

  1. http://www.tothenew.com/blog/handling-large-files-using-javanio-mappedbytebuffer/
  2. https://www.baeldung.com/java-mapped-byte-buffer
于 2019-09-19T16:08:35.743 回答