随机访问中的 FileChannel 与 MappedByteBuffer?

FileChannel vs MappedByteBuffer in random access?

据我所知,MappedByteBuffer有几个好处,比如:

  1. 它将用户space内存地址映射到内核space内存地址,这样就避免了内核space到用户[=44]的内存拷贝=] 从文件读取时

  2. 第一次读取文件中的一块后(缓冲区中从0到100的偏移等),这块会缓存在内存中,所以当你第二次读取缓冲区中的同一块,您是直接从内存而不是从磁盘读取它。

我的问题是:

  1. 我上面的理解对吗?

  2. 如果我的理解是正确的,当你只读一遍的时候(不要再读一遍,这样就不会从内存中读取),使用FileChannel.read是不是一样的(buffer, position) 并使用 MappedByteBuffer.get(byte[], offset, length)?

  3. 对于文件的随机访问(不是重复读取同一块),FileChannel是否会更高效,因为MappedByteBuffer会占用它映射的内存而FileChannel不需要内存?

  4. 我使用 MappedByteBuffer 和我只是将整个文件加载到我的内存中有什么区别。 MappedByteBuffer 的好处是它使用 JVM 堆之外的内存,所以没有 GC 问题?

让我一一为您解答。

As far as I know, MappedByteBuffer has several benefits, such as:

  1. It map the user space memory address to the kernel space memory address, so that it avoids memory copy from kernel space to user space while reading from file

  2. After the first read of a piece in the file (etc an offset from 0 to 100 in the buffer), this piece would be cached in the memory, so when the second time you read the same piece from the buffer, you are reading it from the memory directly but not from the disk.

您的陈述并非无效。 不过,重要的是不要错过简单的事实。文件数据的访问总是涉及缓存(except when it does not)。在内存映射的情况下,来自缓存的页面被映射到您的地址 space,涉及 FileChannel 额外的内存复制。

If my understanding is correct, when you read the piece just once (never read it again so it would not read it from the memory), is it the same by using FileChannel.read(buffer, position) and using MappedByteBuffer.get(byte[], offset, length)?

不,FileChannel.read(buffer, position)涉及额外的内存拷贝。无论如何,数据都会在缓存中挂起一段时间。

For the random accessing to a file (not read the same piece repeatedly), is FileChannel would be more efficient because MappedByteBuffer would take the memory it map while FileChannel need no memory?

你的推理不正确。无论使用哪种数据访问模式,FileChannel 都会将额外的内存复制到内存,而 MappedByteBuffer 则不会。 此外,内存映射本质上是惰性的。只有在访问相应的内存页时才会从磁盘加载数据。

What's difference between I use a MappedByteBuffer and I simply load the whole file into my memory. The benefit of MappedByteBuffer is that it use a memory outside the JVM heap so no GC concern?

您可以映射比盒子上的物理内存大几个数量级的文件(单个 MappedByteBuffer 限制为 2GiB,因此需要多个映射)。一页文件数据访问通过映射随时可能被OS收回。 就GC而言,确实MappedByteBuffer不占heap。

FileChannel和MappedByteBuffer该选什么?

使用内存映射数据还有其他令人讨厌的含义。

  1. 对内存中数据的任何访问都可能成为 IO 操作(如果内存页面未缓存)。 IE。每个 ByteBuffer.get() 调用都可能阻塞。
  2. 无法释放 MappedByteBuffer。内存映射将保持活动状态,直到被 GC 清除。

这使得 MappedByteBuffer 成为一种奇特且很少使用的数据访问方式。

如果如果

建议您避免 MappedByteBuffer
  1. 您的应用程序是交互式的,响应时间很重要。
  2. 您主动使用多线程处理数据(单线程卡在IO上可能会导致其他线程级联阻塞)。
  3. 你想要非阻塞文件 IO