零拷贝
零拷贝
传统IO
基于传统的
while((n = read(diskfd, buf, BUF_SIZE)) > 0)
write(sockfd, buf, n);

整个过程发生了
read 系统调用导致上下文从用户模式切换到内核模式。第一个副本由DMA 引擎执行,DMA 引擎从磁盘读取文件内容并将它们存储到内核地址空间缓冲区中。- 将数据从内核缓冲区复制到用户缓冲区,并且
read 系统调用返回。read 调用返回导致上下文从内核切换回用户模式。现在数据存储在用户地址空间缓冲区中。 write 系统调用导致上下文从用户模式切换到内核模式。执行第三次复制,以再次将数据放入内核地址空间缓冲区。这个时候,数据被放入一个不同的缓冲区,一个与sockets 相关联的缓冲区。- 写系统调用返回,创建我们的第四个上下文切换。独立和异步地,当
DMA 引擎将数据从内核缓冲区传递到协议引擎时,发生第四次复制。
很多数据复制操作并不是真正需要的,可以消除一些复制操作以减少开销并提高性能,在此过程中,我们没有对文件内容做任何修改,那么在内核空间和用户空间来回拷贝数据无疑就是一种浪费,而零拷贝主要就是为了解决这种低效性。零拷贝主要的任务就是避免
COW
零拷贝技术都是减少数据在用户空间和内核空间拷贝技术实现的,但是有些时候,数据必须在用户空间和内核空间之间拷贝。这时候,我们只能针对数据在用户空间和内核空间拷贝的时机上下功夫了。
如果多个程序同时访问同一块数据,那么每个程序都拥有指向这块数据的指针,在每个程序看来,自己都是独立拥有这块数据的,只有当程序需要对数据内容进行修改时,才会把数据内容拷贝到程序自己的应用空间里去,这时候,数据才成为该程序的私有数据。如果程序不需要对数据进行修改,那么永远都不需要拷贝数据到自己的应用空间里。这样就减少了数据的拷贝。