1、基本介绍
-
零拷贝是网络编程的关键,很多性能优化都离不开;
-
在
Java
程序中,常用的零拷贝有mmap
(内存映射) 和sendFile
。那么,他们在OS
里,到底是怎么样的一个的设计?我们分析mmap
和sendFile
这两个零拷贝; -
另外我们看下
NIO
中如何使用零拷贝; -
我们说零拷贝,是从操作系统的角度来说的。因为内核缓冲区之间,没有数据是重复的(只有
kernel buffer
有一份数据); -
零拷贝不仅仅带来更少的数据复制,还能带来其他的性能优势,例如更少的上下文切换,更少的
CPU
缓存伪共享以及无CPU
校验和计算。
2、mmap
优化
mmap
通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据。这样,在进行网络传输时,就可以减少内核空间到用户控件的拷贝次数。如下图:
3、sendFile
优化
Linux 2.1
版本 提供了sendFile
函数,其基本原理如下:数据根本不经过用户态,直接从内核缓冲区进入到 Socket Buffer
,同时,由于和用户态完全无关,就减少了一次上下文切换(零拷贝从操作系统角度,是没有cpu
拷贝),示意图如下:
Linux
在2.4
版本中,做了一些修改,避免了从内核缓冲区拷贝到 Socket buffer
的操作,直接拷贝到协议栈,从而再一次减少了数据拷贝。具体如下图和小结:
这里其实有 一次cpu
拷贝kernel buffer -> socket buffer
。但是,拷贝的信息很少,比如lenght
, offset
, 消耗低,可以忽略。
4、mmap
和 sendFile
的区别
-
mmap
适合小数据量读写,sendFile
适合大文件传输; -
mmap
需要4
次上下文切换,3
次数据拷贝;sendFile
需要3
次上下文切换,最少2
次数据拷贝; -
sendFile
可以利用DMA
方式,减少CPU
拷贝,mmap
则不能(必须从内核拷贝到Socket
缓冲区)。