在开始谈零拷贝之前,首先要对传统的IO方式有一个概念。
基于传统的IO方式,底层实际上通过调用read()和write()来实现。通过read()把数据从硬盘读取到内核缓冲区,再复制到用户缓冲区;然后再通过write()写入到socket缓冲区,最后写入网卡设备。

从上面我们可以看到,一次简单的IO过程产生了4次上下文切换,这个无疑在高并发场景下会对性能产生较大的影响。
零拷贝技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域,这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。
那么对于零拷贝而言,并非真的是完全没有数据拷贝的过程,只不过是减少用户态和内核态的切换次数以及CPU拷贝的次数。
mmap 是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用 read、write 等系统调用函数。
mmap主要实现方式是将读缓冲区的地址和用户缓冲区的地址进行映射,内核缓冲区和应用缓冲区共享,从而减少了从读缓冲区到用户缓冲区的一次CPU拷贝。
mmap的方式节省了一次CPU拷贝,同时由于用户进程中的内存是虚拟的,只是映射到内核的读缓冲区,所以可以节省一半的内存空间,比较适合大文件的传输。

sendfile方法IO数据对用户空间完全不可见,所以只能适用于完全不需要用户空间处理的情况,比如静态文件服务器。

我不是Go不安全包专家-我也不是经验丰富的C程序员。我正在尝试使用mmap系统调用读取一个大于1G的大文件。我使用mmap和munmap而不是读取、写入I/O的原因有很多。那不是重点-我可以在测试中写入文件,当我从文件中读取时,我可以确定字节长度匹配,但我无法读取该字符串文件的内容:(有人可以建议阅读吗?我需要做的更进一步,这是我为示例测试编写的一些代码:filename:="/tmp/dd_file.db"f,err:=os.OpenFile(filename,os.O_RDWR,0666)deferf.Close()iferr!=nil{fmt.Printf("erroropeni
这个简单的python代码:importmmapwithfile("o:/temp/mmap.test","w+b")asfp:m=mmap.mmap(fp.fileno(),0,access=mmap.ACCESS_READ|mmap.ACCESS_WRITE)m.write("Helloworld!")产生以下错误(在mmap.mmap(...)行):WindowsError:[错误1006]文件的卷已被外部更改,因此打开的文件不再有效知道为什么吗? 最佳答案 来自documentation:Iflengthis0,themax
我完全是UNIX项目编译的新手。我在使用Cygwin时需要帮助或建议。“MAKE”命令的一个错误让我心烦意乱:/player_module.cpp:96:undefinedreferenceto`mmap'/player_module.cpp:136:undefinedreferenceto`munmap'player_module.cpp包含:#include#include#include调用代码如下:dump_start=mmap(NULL,sb.st_size,PROT_READ,MAP_SHARED,fileno(file),0);munmap(dump_start,sb.s
我正在尝试将一些linuxC++移植到Windows,但一直停留在这样的一行void*ptr=mmap(NULL,sz,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);我发现这是一种动态分配内存的方法,因为文件描述符是-1。我如何在Windows中执行此操作?我无法在没有文件处理程序的情况下使用MapViewOfFile的文档中找到任何内容。 最佳答案 MapViewOfFile不带文件句柄,它带文件映射句柄。要分配内存块,您可以创建一个匿名文件映射,如下所示:::DWORD
我可以使用java.nio使用Java读/写linuxblock设备。以下代码有效:Pathfp=FileSystems.getDefault().getPath("/dev","sdb");FileChannelfc=null;try{fc=FileChannel.open(fp,EnumSet.of(StandardOpenOption.READ,StandardOpenOption.WRITE));}catch(Exceptione){System.out.println("Erroropeningfile:"+e.getMessage());}ByteBufferbuf=Byt
我开始面临native内存分配问题。我想可能与-Xmx和-Xms设置有关。设置此值的推荐方法是什么?目前我有:-Xmx13G-Xms6G我读到建议设置相同的值,但没有解释原因。我得到的错误是:#ThereisinsufficientmemoryfortheJavaRuntimeEnvironmenttocontinue.#Nativememoryallocation(mmap)failedtomap746061824bytesforcommittingreservedmemory.#Possiblereasons:#ThesystemisoutofphysicalRAMorswapsp
谁能解释一下FSDirectory和MMapDirectory之间的区别是什么?我想预热我的缓存。我读到这可能有用,但找不到这对预热缓存有何帮助。如果您有任何想法,请向我解释。甚至欢迎指点。LucenedocumentationsaysthatMMapusesvirtualmemorytospeedupthelookupoftheindices.如何实现加速以及如果我的索引很大以至于它们不适合我的虚拟内存会发生什么> 最佳答案 MMapDirectory是抽象类FSDirectory的具体子类之一。它使用内存映射文件来访问索引中的信
首先,我是Linux编程的新手,如果这没有意义,或者我找错了树,请向我指出正确的方向,我深表歉意。我正在尝试编写一个cpp应用程序,以在用户区通过pci总线与FPGA通信。到目前为止,我编写的代码枚举了/sys/bus/pci/devices中的目录,检查设备和供应商文件以找到正确的文件。找到设备后,我知道我需要写入的映射区域以某种方式由资源[n]文件表示,但我不确定如何使用它们来读取/写入某些值。从为另一个操作系统编写的代码中,我知道我想与PCI设备的BAR1对话,我(尝试)这样做的方式是使用mmap(这是正确的方式吗?)。首先,我使用O_RDWR获取到/sys/bus/pci/de
我尝试使用mmap函数在虚拟空间中分配大量内存。我的需求是大约30Gb,但它不能。我尝试使用20Gb,结果相同。我在具有60GbRAM的OVH64位机器服务器上执行了我的测试。我的测试代码:#include#include#include#includeintmain(){void*r=NULL;printf("%lu\n",sizeof(size_t));r=mmap(NULL,((size_t)20)*1024*1024*1024,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANONYMOUS,-1,0);printf("%d%s\n",r==MAP_
我遇到了GDB问题和在内核空间中分配的一些缓冲区。缓冲区由一个内核模块分配,该模块应该分配连续的内存块,然后通过mmap()调用将内存映射到用户空间。然而,GDB似乎无法随时访问这些block。例如,在GDB中遇到断点后:(gdb)x/10xb0x4567e0000x4567e000:Cannotaccessmemoryataddress0x4567e000但是,查看/proc//smaps中应用程序当前映射的内存区域显示:4567e000-456d3000rwxs8913f00000:0d883/dev/cmemSize:340kBRss:340kBPss:0kBShared_Cle