概述

零复制(英语:zero-copy;也叫做零拷贝)技术是指计算机执行操作时,cpu不需要先将数据从某处内存复制到另外一个特定区域。这种技术通常通过网络传输文件时节省CPU周期和带宽。

传统IO传输模型

Java零拷贝方式加载图片返回前端 java零拷贝技术_内核

传统IO分析

在Java当中IO存在这三个对象,一个是user space用户空间,一个是kernel space内核空间,还有一个是hardware磁盘对象

  • jvm发起了一次读取事件时,首先会通过内核空间对磁盘进行一次DAM的IO操作,将磁盘中的数据写入到内核空间当中。
  • 再将内核空间中的数据进行一次拷贝,将数据拷贝到用户空间当中
  • jvm发起一次写入事件时,先将用户空间中的数据拷贝到内核空间中
  • 再通过内核空间将数据写入到磁盘中

这种拷贝我们进行了四次拷贝四次上下文切换,这种拷贝和上下文切换极大的消耗时间和性能

网络IO改进版本

Java零拷贝方式加载图片返回前端 java零拷贝技术_Java零拷贝方式加载图片返回前端_02


其实这种模型他也是一种零拷贝,但是它在内核当中多做了一步拷贝过程,将内核空间中的数据拷贝到了socket buffer当中,这是这个模型的一个大缺陷。

它总共进行了两次上下文的切换,和三次拷贝过程

真正的零拷贝

Java零拷贝方式加载图片返回前端 java零拷贝技术_java_03

  • JVM发起读取文件请求时,将文件操作完全交给了系统内核来操作
  • 通过DMA拷贝将数据读取到内核空间当中,再将内核当中的数据头信息(比如:文件名称,文件长度等信息拷贝到socket Buffer中 当然这个过程时间我们可以忽略不记)再将kemel buffer中的数据通过文件引擎,配合socket buffer中的信息一起写入到文件磁盘当中。
  • 当然这种拷贝需要系统支持scatter-and-gather

Java NIO中实现零拷贝的几种方式

DirectByteBuffer

在调用ByteBuffer.allocateDirect()方法获得。JVM将使用malloc()方法在堆内存之外分配内存空间。因为它不是由JVM管理,所以你的内存空间是页面对其的,不受GC影响 ,这使得它成为处理本地代码的完美选择。然而你需要像C程序员一样,自己管理内存。

MappedByteBuffer

零拷贝是操作系统底层的一种实现,我们在网络编程中,利用操作系统这一特性,可以大大提高数据传输的效率。这也是目前网络编程框架中都会采用的方式,理解好零拷贝,有助于我们进一步学习Netty等网络通信框架的底层原理。