java - 随机访问中的 FileChannel 与 MappedByteBuffer?

标签 java linux garbage-collection nio mmap

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

  1. 将用户空间的内存地址映射到内核空间的内存地址,从而避免了读取文件时从内核空间到用户空间的内存拷贝

  2. 在第一次读取文件中的一 block 之后(缓冲区中从 0 到 100 的偏移量),该 block 将缓存在内存中,因此当您第二次从文件中读取同一 block 时缓冲区,您是直接从内存而不是从磁盘读取它。

我的问题是:

  1. 我上面的理解对吗?

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

  3. 对于随机访问文件(不是重复读取同一 block ),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)。在内存映射的情况下,来自缓存的页面被映射到您的地址空间,涉及 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,因此需要多个映射)。一页文件数据访问通过映射可以随时被操作系统收回。 就GC而言,MappedByteBuffer确实不占堆。

FileChannel 和 MappedByteBuffer 怎么选?

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

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

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

如果会建议您避免 MappedByteBuffer if

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

关于java - 随机访问中的 FileChannel 与 MappedByteBuffer?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49996217/

相关文章:

linux - 如何在脚本中包含和排除字符串

java - 使用 Java 的 ReferenceQueue

java - 我的 Swing 应用程序是否分配了冗余对象?

java - "Inspect Element"Java UI 工具

java - 为什么 RxNetty 使用线程池?

Java SE 11.0.5 (LTS) 许可证(下载最新的 openJDK 更新)

linux - 没有可用的符号表信息

java - 榛树数据分布

php - 通过绝对路径在 PHP 中包含文件的问题

python - Python GC 会像这样处理引用循环吗?