对于所有的io操作,底层一定是调用操作系统的api来进行读写。受限于不同的操作系统,操作方式一定是有差异的。以下read和write操作,可以看做服务器从磁盘硬件上读取文件数据,然后通过socket发送给客户端的流程

传统io服务端对客户端的传输

对于读操作:jvm虚拟机一定会发送一个read()操作系统级别的方法,由此会产生一个上下文的切换,从程序所在的用户空间切换至系统的内核空间,内核空间向磁盘空间请求数据,通过DMA直接内存访问的方式将数据读取到内核空间缓冲区,此时用户空间是无法直接使用的,所以下面会将这份缓冲数据原封不动的拷贝到用户空间,至此read操作就结束。期间有两次上下文的切换,和两次数据的拷贝

对于写操作:将文件读取之后需要发送给远端socket客户端。同样调用系统级别的write方法,需要将上述读到的用户空间的数据原封不动的拷贝到内核上的socket缓冲区,然后DMA 引擎将数据从该缓冲区传到协议引擎,这一次拷贝独立地、异步地发生 。

对于这种io的操作,用户空间只是作为一个中转站,会和内核空间有不必要的上下文切换和数据之间的拷贝

操作系统对于io的一种优化方式

对于优化方式,需要系统直接的支持,jvm是无法提供任何的帮助。对于传统的linux、unix等操作系统是支持的

对于读写操作:用户空间向操作系统发送sendfile()方法,后续的操作只会在内核空间完成。对于所有的读写操作将只会有两次的用户空间和内核空间切换,这种操作称为操作系统意义上的零拷贝。同样的后续会通过DMA的方式向磁盘空间读取数据,读到内核空间的缓冲区,然后将这部分数据写到socket缓冲区,然后通过socket缓冲区向客户端发送数据,完成之后向内核空间然后向用户空间发送数据。相比于第一种方式有了极大的改善。

io的进一步优化方式

相对于上一种方案,内核空间会将数据复制一份到socket缓冲区,因为对于DMA直接内存访问的机制,希望内存地址是连续的,当然buffer的地址是连续的,因此会多一步拷贝到socket缓冲区,如果操作系统支持buffer中的scatter/gather,那么我们就能够有效的避免这种问题。可以通过scatter/gather的方式来读取数据到内核空间然后直接进行后续的写操作,从而减少中间的一步拷贝。

最佳的方式

通过DMA的方式拷贝数据到内核缓冲区,将对应的文件描述符写到socket buffer中,包含了内核的缓冲区的地址和数据长度,并不需要将数据拷贝到socket buffer中,只用存文件描述符。最后协议引擎发送数据的时候,从kernel buffer和socket buffer里面读取数据,对于kernel buffer是真实数据的读取,而对于socket buffer是文件描述符的读取,通过gather操作最终一起发送给客户端

很多的web应用程序都支持零拷贝,比如apache和tomcat,Java中提供的nio的方式是通过transferTo来实现

对于我们上面所述的所有方式,用户是无法对文件进行一定的操作。我们可以通过内存映射在中间过程来对文件进行一定的操作:

参考:

http://xcorpion.tech/2016/09/10/It-s-all-about-buffers-zero-copy-mmap-and-Java-NIO/ 
https://www.ibm.com/developerworks/library/j-zerocopy/

http://www.linuxjournal.com/article/6345?page=0,0

java-nio之zero copy深入分析的更多相关文章

  1. Java NIO使用及原理分析(1-4)(转)

    转载的原文章也找不到!从以下博客中找到http://blog.csdn.net/wuxianglong/article/details/6604817 转载自:李会军•宁静致远 最近由于工作关系要做一 ...

  2. 攻破JAVA NIO技术壁垒

    转载自攻破JAVA NIO技术壁垒 概述 NIO主要有三大核心部分:Channel(通道),Buffer(缓冲区), Selector.传统IO基于字节流和字符流进行操作,而NIO基于Channel和 ...

  3. Java Se : Java NIO(服务端)与BIO(客户端)通信

    Java目前有三种IO相关的API了,下面简单的说一下: BIO,阻塞IO,最常用的Java IO API,提供一般的流的读写功能.相信学习Java的人,都用过. NIO,非阻塞IO,在JDK1.4中 ...

  4. Java NIO 基础

    Java在JDK1.4中引入了 java.nio 类库,为Java进军后端Server和中间件开发打开了方便之门. 一般而言,这里的 nio 代表的是 New I/O,但是从实质上来说,我们可以将其理 ...

  5. Java NIO教程 文件系统

    在NIO.2的文件系统中,Path是一切操作的基础.Path准确来说,代表着文件系统中的位置.可以代表一个目录(也就是通常所说的文件夹),也可以代表一个文件. 在新文件系统中,还有一个不得不说的就是F ...

  6. Java NIO教程 MappedByteBuffer

    之前跟大家说过,要讲MappedByteBuffer,现在我来履行承诺了. 首先从大体上讲一下MappedByteBuffer究竟是什么.从继承结构上来讲,MappedByteBuffer继承自Byt ...

  7. JAVA NIO是什么(zz)

    JAVA NIO是什么? 1.   基本 概念 IO 是主存和外部设备 ( 硬盘.终端和网络等 ) 拷贝数据的过程. IO 是操作系统的底层功能实现,底层通过 I/O 指令进行完成. 所有语言运行时系 ...

  8. Java NIO、NIO.2学习笔记

    相关学习资料 http://www.molotang.com/articles/903.html http://www.ibm.com/developerworks/cn/education/java ...

  9. 【转载】高性能IO设计 & Java NIO & 同步/异步 阻塞/非阻塞 Reactor/Proactor

    开始准备看Java NIO的,这篇文章:http://xly1981.iteye.com/blog/1735862 里面提到了这篇文章 http://xmuzyq.iteye.com/blog/783 ...

  10. Java Nio 多线程网络下载

    --> 默认最多50个线程 同一文件下载失败延迟超过30秒就结束下载 --> 下载5分钟超时时间,假设5分钟内未下载完就结束下载 --> 依赖 commons-httpclient ...

随机推荐

  1. Ubuntu 18.04 上设置桌面程序开机自启动

    需求 在新安装的 Ubuntu 18.04 系统上,将有些不可描述的程序开机之后自动启动 Startup Applications Preferences 打开 Startup Application ...

  2. 003.LVM扩容

    一 LVM扩容步骤 创建分区 创建PV 扩容VG 扩容LV 载大小 二 创建分区 使用分区工具(如fdisk等)创建LVM分区,却将分区标识为LVM的分区类型8e. [root@kauai ~]# f ...

  3. 使用Synchronized块同步变量

    我们可以通过synchronized块来同步特定的静态或非静态方法.要想实现这种需求必须为这些特定的方法定义一个类变量,然后将这些方法的代码用synchronized块括起来,并将这个类变量作为参数传 ...

  4. Python进行Android开发步骤

    移动应用开发 1. 建立开发环境 下载软件开发包(SDK):        http://developer.android.com/sdk/index.html        adt-bundle- ...

  5. react的非DOM操作

    非dom属性?dangerouslySetInnerHTML,ref,key非dom标准属性,也就是说dom标准里面没有规定的属性,react引入了三个非dom属性,如上. dangerouslySe ...

  6. KVM源代码解读:linux-3.17.4\include\linux\kvm_host.h

    #ifndef __KVM_HOST_H #define __KVM_HOST_H /* * This work is licensed under the terms of the GNU GPL, ...

  7. 【BZOJ-2142】礼物 拓展Lucas定理

    2142: 礼物 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 1313  Solved: 541[Submit][Status][Discuss] ...

  8. Centos7 安装 ActiveMQ 5.15.1

    环境 [root@node1 ~]# cat /etc/redhat-release CentOS Linux release (Core) [root@node1 ~]# uname -r -.el ...

  9. .Net中常用的重要的第三方组件

    RSS.NET.dll RSS.NET是一款操作RSS feeds的开源.NET类库.它为解析和编写RSS feeds提供了一个可重用的对象模型.它完全兼容RSS 0.90, 0.91, 0.92, ...

  10. LPC43xx SGPIO Slice 输入输出连接表