知识补充:
1、DMA是直接内存访问(Direct Memory Access) 技术,早期 DMA 只存在在主板上,如今由于 I/O 设备越来越多,数据传输的需求也不尽相同,所以每个 I/O 设备里面都有自己的 DMA 控制器。
2、每次系统调用都得先从用户态切换到内核态,等内核完成任务后,再从内核态切换回用户态。
我们都听过 kafka 很快,其中一个原因是 kafka 使用零拷贝。看看从文件中读取数据并通过网络将数据传输到另一个程序的场景,在内部的复制操作,需要在用户模式和内核模式之间进行四次上下文切换,并且进行数据复制四次。
完成所有四个操作后,它将再次切换到用户模式。
回顾以上动作,其实发现实际上第二个和第三个数据拷贝是可以避免的。JAVA 类库通过 java.nio.channels 中的 transferTo() 方法在 UNIX 系统上执行零副本,使用零拷贝的应用程序请求内核直接将数据从磁盘文件复制到套接字,而不通过应用程序。零拷贝极大提高了应用程序性能,并减少了内核和用户模式之间的上下文切换次数。
我们看看 transferTo() 是如何复制数据的?
这里我们还需要 3 个副本和 2 个上下文切换。
但当前还没有达到零拷贝,如果底层网卡支持收集操作,可以进一步减少内核重复拷贝数据的操作。在 linux 内核 2.4 及更高版本中,套接字缓冲区描述符支持该场景。
Kafka 和 Nginx 都有实现零拷贝技术,这将大大提高文件传输的性能。拷贝技术,本质上讲就是通过减少非必要的内存拷贝以及上下文切换,来提高文件在通道间复制速度的一种技术。以本文中的transferTo()方法为例,通过该技术,可以将原来四次内存间拷贝减少成两次,将四次上下文切换减少成两次,大大提高复制的速度。但零拷贝技术并非万能的,它有自己的使用场景,对于将大量数据从一个 I/O 通道复制到另一个通道的情况(例如 Web 服务器),都是合适的。