零拷贝基本介绍

1.零拷贝是网络编程的关键,很多性能优化都离不开。
2.在 Java 程序中,常用的零拷贝有 mmap(内存映射)和 sendFile。那么,他们在 OS 里,到底是怎么样的一个的设计?我们分析 mmap 和 sendFile 这两个零拷贝
3.另外我们看下 NIO 中如何使用零拷贝

传统 IO 数据读写

Java 传统 IO 和网络编程的一段代码

File file = new File("test.txt");
RandomAccessFile raf = new RandomAccessFile(file, "rw");byte[] arr = new byte[(int) file.length()];
raf.read(arr);Socket socket = new ServerSocket(8080).accept();
socket.getOutputStream().write(arr);

分析在以上传统的IO数据读写中,发生了多少次文件的拷贝以及用户态和内核态的状态切换。

传统 IO 模型

DMA:direct memory access 直接内存拷贝(不使用 CPU)

可以看到图中上面一部分代表状态的切换,user context代表用户态,kernel context代表内核态。

从整个模型来看,他首先把硬件hard disk上的数据进行DMA拷贝,也就是在读的过程中,我们用了read方法,它首先把硬盘上的数据经过DMA拷贝,拷贝到内核buffer,然后再用CPU拷贝,拷贝到我们的用户buffer,数据在用户buffer中进行修改。修改完之后,再用CPU拷贝,拷贝到socketbuffer,然后再用DMA拷贝,拷贝到协议栈protocol engine

传统IO经历了4次拷贝,3次状态切换。

mmap 优化(memory map内存映射)

1.mmap 通过内存映射,将文件映射到内核缓冲区,同时,用户空间可以共享内核空间的数据。这样,在进行网络传输时,就可以减少内核空间到用户空间的拷贝次数。如下图
2.mmap 示意图

如果使用了内存映射技术,第一次DMA拷贝还是有的,即DMA将硬件中的内容拷贝到内核,由于kernel buffer和user buffer可以共享数据,此时这个地方就不会发生CPU拷贝,数据可以直接在内核缓冲进行修改。修改完了之后再通过CPU拷贝到socket buffer.然后再通过socket buffer经过DMA拷贝到协议栈。

在mmap优化之后,状态切换次数没有改变,仍是3次,拷贝次数变为3次。

sendFile 优化

Linux2.1 版本提供了 sendFile 函数,其基本原理如下:数据根本不经过用户态,直接从内核缓冲区进入到 SocketBuffer,同时,由于和用户态完全无关,就减少了一次上下文切换
示意图和小结


第一次仍然是通过DMA拷贝将硬件数据转移到内核buffer,然后经过CPU拷贝到socketbuffer,然后再通过DMA拷贝到协议栈

由4次拷贝减少到到3次,状态切换变为2次。

3.提示:零拷贝从操作系统角度,是没有 cpu 拷贝

不可能数据读取不经过内核

4.Linux在2.4 版本中,做了一些修改,避免了从内核缓冲区拷贝到 Socketbuffer 的操作,直接拷贝到协议栈,从而再一次减少了数据拷贝。具体如下图和小结:


先经过DMA拷贝到内核buffer,此时socket buffer变成灰色,指的是内核buffer可以直接进行DMA拷贝到协议栈。当然,很少的数据还是可能会有一次CPU拷贝,从内核buffer到socket buffer,但是数据量很少,比如kernel buffer的长度,size,消耗低,可以忽略。

5.这里其实有一次 cpu 拷贝 kernel buffer -> socket buffer 但是,拷贝的信息很少,比如 lenght、offset 消耗低,可以忽略

所以由4次拷贝变为2次。CPU拷贝变为0次。由3次上下文切换变为2次。

零拷贝的再次理解
1.我们说零拷贝,是从操作系统的角度来说的。因为内核缓冲区之间,没有数据是重复的(只有 kernel buffer 有一份数据,而前面的方法中从kernel buffer经过CPU拷贝到socket buffer,有两份数据)。

2.零拷贝不仅仅带来更少的数据复制,还能带来其他的性能优势,例如更少的上下文切换,更少的 CPU 缓存伪共享以及无 CPU 校验和计算

mmap 和 sendFile 的区别

1.mmap 适合小数据量读写,sendFile 适合大文件传输。

2.mmap 需要 4 次上下文切换,3 次数据拷贝;sendFile 需要 3 次上下文切换,最少 2 次数据拷贝。

3.sendFile 可以利用 DMA 方式,减少 CPU 拷贝,mmap 则不能(必须从内核拷贝到 Socket

NIO 零拷贝案例

案例要求:

1.使用传统的 IO 方法传递一个大文件

2.使用 NIO 零拷贝方式传递(transferTo)一个大文件

3.看看两种传递方式耗时时间分别是多少

NewIOServer.javapackage com.atguigu.nio.zerocopy;import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;//服务器
public class NewIOServer {public static void main(String[] args) throws Exception {InetSocketAddress address = new InetSocketAddress(7001);ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();ServerSocket serverSocket = serverSocketChannel.socket();serverSocket.bind(address);//创建bufferByteBuffer byteBuffer = ByteBuffer.allocate(4096);while (true) {SocketChannel socketChannel = serverSocketChannel.accept();int readcount = 0;while (-1 != readcount) {try {readcount = socketChannel.read(byteBuffer);} catch (Exception ex) {// ex.printStackTrace();break;}//byteBuffer.rewind(); //倒带 position = 0 mark 作废}}}
}
NewIOClient.javapackage com.atguigu.nio.zerocopy;import java.io.FileInputStream;
import java.net.InetSocketAddress;
import java.nio.channels.FileChannel;
import java.nio.channels.SocketChannel;public class NewIOClient {public static void main(String[] args) throws Exception {SocketChannel socketChannel = SocketChannel.open();socketChannel.connect(new InetSocketAddress("localhost", 7001));String filename = "protoc-3.6.1-win32.zip";//得到一个文件channelFileChannel fileChannel = new FileInputStream(filename).getChannel();//准备发送long startTime = System.currentTimeMillis();//在 linux 下一个 transferTo 方法就可以完成传输//在 windows 下一次调用 transferTo 只能发送 8m, 就需要分段传输文件,而且要主要//传输时的位置=》课后思考...//transferTo 底层使用到零拷贝long transferCount = fileChannel.transferTo(0, fileChannel.size(), socketChannel);System.out.println("发送的总的字节数 = " + transferCount + " 耗时: " + (System.currentTimeMillis() - startTime));//关闭fileChannel.close();}
}

Java AIO 基本介绍

JDK7 引入了 AsynchronousI/O,即 AIO。在进行 I/O 编程中,常用到两种模式:Reactor 和 Proactor。Java 的 NIO 就是 Reactor,当有事件触发时,服务器端得到通知,进行相应的处理

AIO 即 NIO2.0,叫做异步不阻塞的 IO。AIO 引入异步通道的概念,采用了 Proactor 模式,简化了程序编写,有效的请求才启动线程,它的特点是先由操作系统完成后才通知服务端程序启动线程去处理,一般适用于连接数较多且连接时间较长的应用

目前 AIO 还没有广泛应用,Netty 也是基于 NIO,而不是 AIO,因此我们就不详解 AIO 了,有兴趣的同学可以参考《Java新一代网络编程模型AIO原理及Linux系统AIO介绍》

BIO、NIO、AIO 对比表

BIO NIO AIO
IO模型 同步阻塞 同步非阻塞(多路复用) 异步非阻塞
编程难度 简单 复杂 复杂
可靠性
吞吐量

举例说明

1.同步阻塞:到理发店理发,就一直等理发师,直到轮到自己理发。

2.同步非阻塞:到理发店理发,发现前面有其它人理发,给理发师说下,先干其他事情,一会过来看是否轮到自己.

3.异步非阻塞:给理发师打电话,让理发师上门服务,自己干其它事情,理发师自己来家给你理发

NIO与零拷贝和AIO相关推荐

  1. NIO效率高的原理之零拷贝与直接内存映射

    前言 在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,点击查看. 这篇博客将针对第三个原因,进行更详细的讲解. 首先澄清,零拷贝与内存直接映射并不是Java中独有的概念,并 ...

  2. NIO、BIO编程模型与零拷贝

    Java IO模型 Java共支持3种网络编程模型/IO模式:BIO.NIO.AI BIO 同步并阻塞(传统阻塞型),服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进 ...

  3. jvm 堆外内存_NIO效率高的原理之零拷贝与直接内存映射

    更多内容,欢迎关注微信公众号:全菜工程师小辉~ 前言 在笔者上一篇博客,详解了NIO,并总结NIO相比BIO的效率要高的三个原因,彻底搞懂NIO效率高的原理. 这篇博客将针对第三个原因,进行更详细的讲 ...

  4. 【Netty】零拷贝案例 ( transferTo | transferFrom )

    文章目录 一. 案例需求 二. 传统 BIO 拷贝案例 三. 零拷贝案例 服务器端 四. 零拷贝案例 客户端 五. 零拷贝案例 运行与分析 一. 案例需求 给出两个案例 , 一个是 使用普通的 BIO ...

  5. 【Netty】Netty零拷贝原理

    前言 理解零拷贝 零拷贝是Netty的重要特性之一,而究竟什么是零拷贝呢? WIKI中对其有如下定义: "Zero-copy" describes computer operati ...

  6. 彻底搞懂Netty高性能之零拷贝

    作为Java网络编程学习者,不仅要知道NIO,还一定要学习Mina和Netty这两个优秀的网络框架.作为上一篇NIO效率高的原理之零拷贝与直接内存映射的补充,本文将针对Netty的零拷贝特性进行详细分 ...

  7. 四十七、Netty零拷贝

    零拷贝的定义 Zero-copy, 就是在操作数据时, 不需要将数据 buffer 从一个内存区域拷贝到另一个内存区域. 因为少了一次内存的拷贝, 因此 CPU 的效率就得到的提升. 在 OS 层面上 ...

  8. java基础巩固-宇宙第一AiYWM:为了维持生计,四大基础之OS_Part_2整起~IO们那些事【包括五种IO模型:(BIO、NIO、IO多路复用、信号驱动、AIO);零拷贝、事件处理及并发等模型】

    PART0.前情提要: 通常用户进程的一个完整的IO分为两个阶段(IO有内存IO.网络IO和磁盘IO三种,通常我们说的IO指的是后两者!):[操作系统和驱动程序运行在内核空间,应用程序运行在用户空间, ...

  9. 从BIO到NIO、AIO和零拷贝

    文章目录 从BIO到NIO.AIO和零拷贝 BIO NIO AIO 零拷贝 结论 从BIO到NIO.AIO和零拷贝 在JAVA的网络编程方面,BIO.NIO.AIO和零拷贝是我们必须掌握的技术,它们分 ...

最新文章

  1. 编程 25 年后,现实将我打回菜鸟程序员的起点
  2. curl比较有用的参数
  3. c语言pause()函数(让进程暂停直到信号出现)
  4. python习题集整理汇总
  5. 我的世界java版使用剑_我的世界:JAVA版藏“私货”内置绝世好剑与神功,你玩的版本有吗...
  6. MyBatis 多表关联相同字段的解决方案
  7. Delphi 的绘图功能[5] - 获取 Canvas 对象
  8. 计算机二级与c语言有什么关系,计算机二级c和c++区别?
  9. 人脸识别常用开源数据集大全
  10. 什么是TTL电平和cmos电平?ttl电平和cmos电平的区别是什么?
  11. Win10预览版之BUG
  12. 01【计算机基础、Java概述】
  13. js修改div标签中的内容
  14. php汉字占几个字节,php一个汉字几个字节
  15. sin和cos的爱恋
  16. Mahalanobis距离(马氏距离)的“哲学”解释
  17. Remote Dictionary Server(Redis)——基于 KV 结构的作为 Cache 使用的 NoSQL 数据库管理系统
  18. 从未在一起更让人遗憾_从未在一起和在一起后分开,哪个更遗憾?
  19. 1个系统节拍 c语言_【菜鸡C语言】菜鸡鼓起勇气用Dev-c++打起节奏来了
  20. Spring 的自动装配

热门文章

  1. 原来微信可以自定义!把这些功能全关闭后 真清爽!
  2. 章泽天卸任刘强东旗下一公司董事
  3. 苹果罕见人事大调整:多个项目被迫暂停 员工“惊慌失措”
  4. 拳王虚拟项目公社:自动化的虚拟资源产品,唱歌教程赚地盆满钵满
  5. C语言结构体对齐[转]
  6. mysql5.6 load_MySQL 5.6 dump/load buffer pool实验
  7. es创建索引设置字段不分词_java整合es指定字段不分词搜索
  8. BMP图片读写接口函数
  9. linux下CPP的认识
  10. 【Elasticsearch】 es watcher 视频 笔记