繁体   English   中英

为什么mmap()(内存映射文件)比read()更快

[英]Why mmap() (Memory Mapped File) is faster than read()

我最近正在研究Java NIO的MappedByteBuffer。 我已经阅读了一些关于它的帖子,所有人都提到“mmap()比read()更快”

在我的结论中:

  1. 我对待MappedByteBuffer == Memory Mapped File == mmap()

  2. read()必须通过以下方式读取数据:磁盘文件 - >内核 - >应用程序,因此它具有上下文切换和缓冲区复制

  3. 他们都说mmap()比read()具有更少的复制或系统调用,但据我所知,它还需要在您第一次访问文件数据时从磁盘文件中读取。 所以第一次读它:虚拟地址 - >内存 - >页面错误 - >磁盘文件 - >内核 - >内存。 除了你可以随机访问它,最后3个步骤(磁盘文件 - >内核 - >内存)与read()完全相同,那么mmap()如何比read()更少复制或系统调用?

  4. mmap()和交换文件之间的关系是什么,os是否会将最少使用的内存文件数据放入交换(LRU)? 因此,当您第二次访问这些数据时,操作系统会从交换但不是磁盘文件中检索它们(不需要复制到内核缓冲区),这就是为什么mmap()复制和系统调用较少的原因?

  5. 在java中,MappedByteBuffer是从堆中分配的(它是一个直接缓冲区)。 所以当你从MappedByteBuffer中读取时,是否意味着它需要从Java堆外部再添加一个额外的内存副本到java堆中?

谁能回答我的问题? 谢谢 :)

1:是的,这基本上就是MappedByteBuffer。

2:“磁盘文件 - >内核”不一定涉及复制。

3:使用内存映射文件,一旦内核将文件读入其缓存,它就可以简单地将缓存的那部分映射到您的进程中 - 而不必将数据从缓存复制到您的进程指定的位置。

4:如果内核决定从内存映射文件中换出页面,它将不会将页面写入页面文件; 在丢弃页面之前,它会将页面写入原始文件(从中映射的文件)。 将其写入页面文件将是不必要的并浪费页面文件空间。

5:是的。 例如,如果调用get(byte[])则数据将从堆外映射复制到数组中。 请注意,诸如get(byte[])函数需要复制任何类型缓冲区的数据 - 这不是特定于内存映射文件的。

你在比较苹果和橘子。 mmap() '比read()更快,因为它不执行任何I / O. 当您访问由映射产生的内存地址时,I / O将延迟到。 I / O是一样一样read(),并且不管 I / O快于read()是一个很有争议的问题。 在我接受之前,我希望看到一个合适的基准。

我对待MappedByteBuffer == Memory Mapped File == mmap()

好。

read()必须通过以下方式读取数据:磁盘文件 - >内核 - >应用程序,因此它有两次上下文切换和缓冲区复制

相比什么?

他们都说mmap()比read(),有更少的复制或系统调用read(),

它具有较少的系统调用。 它是否具有较少的复制取决于实现。 当然可以通过DMA直接读取和写入数据,但特定的操作系统是否是特定于操作系统的。

但据我所知,它还需要在您第一次访问文件数据时从磁盘文件中读取。

正确。

所以第一次读它:虚拟地址 - >内存 - >页面错误 - >磁盘文件 - >内核 - >内存。 除了你可以随机访问它,最后3个步骤(磁盘文件 - >内核 - >内存)与read()完全相同,那么mmap()如何比read()更少复制或系统调用?

因为DMA,如果实现的话。

mmap()和交换文件之间的关系是什么

分配给映射的内存是进程地址空间的一部分,它是虚拟的,并且需要进行交换,并且交换文件中必须有空间,就像任何其他内存一样。

是os将把最少使用的内存文件数据放入交换(LRU)?

没有。

因此,当您第二次访问这些数据时,操作系统会从交换但不是磁盘文件中检索它们(不需要复制到内核缓冲区),这就是为什么mmap()复制和系统调用较少的原因?

不。做所有这些都是错的。

在java中, MappedByteBuffer是从堆中分配的(它是一个直接缓冲区)。

这没有意义。 直接缓冲区不会从堆中分配,它们由mmap()或平台API分配,作为内存。 不在堆中。 MappedByteBuffer是直接缓冲区是正确的。

所以当你从MappedByteBuffer中读取时,是否意味着它需要从Java堆外部再添加一个额外的内存副本到java堆中?

是的,但不是出于上述原因。 原因是你必须调用MappedByteBuffer.get()/put(),这本身就是一个额外的步骤。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM