Java 为什么mmap()(内存映射文件)比read()快
最近,我正在研究Java NIO的MappedByteBuffer。 我读过一些关于它的帖子,它们都提到“mmap()比read()快。” 我的结论是:Java 为什么mmap()(内存映射文件)比read()快,java,c,linux,io,operating-system,Java,C,Linux,Io,Operating System,最近,我正在研究Java NIO的MappedByteBuffer。 我读过一些关于它的帖子,它们都提到“mmap()比read()快。” 我的结论是: 我处理MappedByteBuffer==内存映射文件==mmap() read()必须通过磁盘文件->内核->应用程序读取数据,因此它具有上下文切换和缓冲区复制功能 他们都说mmap()的复制或系统调用比read()少,但我知道它还需要在您第一次访问文件数据时从磁盘文件中读取。所以它第一次读到:虚拟地址->内存->页面错误->磁盘文件->内核
有人能回答我的问题吗?谢谢:)你在比较苹果和桔子
mmap()
比read()
快,因为它不做任何I/O。I/O延迟到您访问映射产生的内存地址时。该I/O与read(),
非常相似,并且该I/O是否比read()
快是一个非常没有意义的问题。在我接受之前,我希望看到一个合适的基准
我处理MappedByteBuffer
==内存映射文件==mmap()
嗯
read()
必须通过磁盘文件->内核->应用程序读取数据,因此它有两次上下文切换和缓冲区复制
和什么相比
他们都说mmap()的复制或系统调用比read(),
它的系统调用更少。它是否具有较少的复制取决于实现。当然,通过DMA直接读取和写入数据是可能的,但具体操作系统是否这样做取决于具体操作系统
但据我所知,它还需要在您第一次访问文件数据时从磁盘文件中读取数据
对
所以它第一次读到:虚拟地址->内存->页面错误->磁盘文件->内核->内存。除了可以随机访问之外,最后3个步骤(磁盘文件->内核->内存)与read()完全相同,那么mmap()的复制或系统调用如何比read()少呢
因为DMA,如果实现的话
mmap()和交换文件之间的关系是什么
分配给映射的内存是进程地址空间的一部分,它是虚拟的,需要交换,交换文件中必须有空间容纳它,就像其他内存一样
操作系统是否会将内存中使用最少的文件数据放入交换(LRU)
没有
所以,当您第二次访问这些数据时,操作系统从交换文件而不是磁盘文件中检索它们(无需复制到内核缓冲区),这就是为什么mmap()的复制和系统调用更少的原因
不,那样做是完全错误的
在java中,MappedByteBuffer
从堆中分配(它是一个直接缓冲区)
那没有道理。直接缓冲区不是从堆中分配出来的,它们是由mmap()
或任何平台API分配的,作为新内存。不在堆里。正确的说法是,MappedByteBuffer
是直接缓冲区
那么,当您从MappedByteBuffer读取时,是否意味着它需要从java堆外部向java堆中多复制一个内存
是的,但不是因为上述原因。原因是您必须调用
MappedByteBuffer.get()/put(),
,这本身就是一个额外的步骤。1:是的,这本质上就是MappedByteBuffer
2:“磁盘文件->内核”不一定涉及复制
3:使用内存映射文件,一旦内核将文件读入其缓存,它就可以简单地将缓存的该部分映射到进程中,而不必将数据从缓存复制到进程指定的位置
4:如果内核决定从内存映射文件中交换一个页面,它将不会将该页面写入该页面文件;在丢弃页面之前,它会将页面写入原始文件(它的映射源文件)。将其写入页面文件是不必要的,并且会浪费页面文件空间
5:是的。例如,如果调用
get(byte[])
,则数据将从堆外映射复制到数组中。请注意,诸如get(byte[])
之类的函数需要为任何类型的缓冲区复制数据-这并不特定于内存映射文件。对于第4部分,操作系统磁盘缓存似乎也考虑到了这一点。除了使用模式带来的最终性能好处外,内存映射文件在某种程度上比堆缓冲区更适合共享机器。当操作系统需要回收物理内存时,可以保存和取消映射内存映射文件,当程序再次访问它们时,可以透明地重新映射。我不会称之为“比较苹果和桔子”。这两种机制共享读取和写入文件的目的。听起来很像。@zneak Comparingmmap()
与read()。事实上,OP似乎在质疑这一说法。我认为他对使用mmap
读取与您相同的数据的全球性能更感兴趣