FileChannel与MappedByteBuffer随机访问?

时间:2018-04-24 07:53:11

标签: java linux garbage-collection nio mmap

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

  1. 它将用户空间内存地址映射到内核空间内存地址,以便在从文件读取时避免从内核空间到用户空间的内存复制

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

  3. 我的问题是:

    1. 我的理解是否正确?

    2. 如果我的理解是正确的,当你只读一次这个片段时(从不再读它,因此它不能从内存中读取它),使用FileChannel.read(缓冲区,位置)是否相同使用MappedByteBuffer.get(byte [],offset,length)?

    3. 对于随机访问文件(不重复阅读同一篇文章),FileChannel会更有效率,因为MappedByteBuffer会占用它映射的内存而FileChannel不需要内存吗?

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

1 个答案:

答案 0 :(得分:2)

让我逐一回答你的问题。

  

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

     
      
  1. 它将用户空间内存地址映射到内核空间内存地址,以便在从文件读取时避免从内核空间到用户空间的内存复制

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

  4.   

您的陈述无效。 但是,重要的是不要错过简单的事实。文件数据的访问始终涉及缓存(except when it does not)。如果内存映射来自缓存的页面映射到您的地址空间,则涉及FileChannel额外的内存复制。

  

如果我的理解是正确的,当你只读一次(从不再读它,因此它不会从内存中读取它)时,使用FileChannel.read(缓冲区,位置)和使用MappedByteBuffer是否相同。 get(byte [],offset,length)?

不,FileChannel.read(缓冲区,位置)涉及额外的内存复制。无论如何,数据将在缓存中挂起一段时间。

  

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

您的推理不正确。使用数据访问模式,FileChannel为内存副本执行额外的内存,MappedByteBuffer不会。 另外,内存映射本质上是懒惰的。只有在访问相应的内存页时才会从磁盘加载数据。

  

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

您可以在框上映射大于物理内存的数量级的文件(单个MappedByteBuffer限制为2GiB,因此需要多个映射)。通过映射的文件数据访问页面可以随时被OS收回。 实际上,就GC而言,MappedByteBuffer并不占用堆。

在FileChannel和MappedByteBuffer之间选择什么?

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

  1. 对内存中数据的任何访问都可能成为IO操作(如果未缓存内存页)。即每个ByteBuffer.get()调用都可能阻塞。
  2. 无法处理MappedByteBuffer。内存映射将保持活动状态,直到GC清除为止。
  3. 这使得MappedByteBuffer成为一种奇特的,很少使用的方式来访问数据。

    如果建议您避免 MappedByteBuffer

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