原文出处: http://www.ibm.com/developerworks/library/j-zerocopy/

传统的I/O

使用传统的I/O程序读取文件内容, 并写入到另一个文件(或Socket), 如下程序:

File.read(fileDesc, buf, len);
Socket.send(socket, buf, len);

会有较大的性能开销, 主要表现在一下两方面:

1. 上下文切换(context switch), 此处有4次用户态和内核态的切换

2. Buffer内存开销, 一个是应用程序buffer, 另一个是系统读取buffer以及socket buffer

其运行示意图如下

1) 先将文件内容从磁盘中拷贝到操作系统buffer

2) 再从操作系统buffer拷贝到程序应用buffer

3) 从程序buffer拷贝到socket buffer

4) 从socket buffer拷贝到协议引擎.

这是上下文切换图

1) 调用read(), 程序切换到内核态

2) read()调用完毕, 返回数据, 程序切换回用户态

3) 调用send(), 程序切换到内核态

4) send()完毕, 程序切换回用户态

操作系统使用 read buffer 的好处是"预读", 当你的程序需要对文件数据做处理, 并且每次读取的数据小于read buffer 的时候, 可以先将多数数据预读到 read buffer, 这样程序在读取的时候效率会更高. 但是当你需要读取的数据大于操作系统的read buffer的时候, read buffer则会成为累赘.

另外, 在你的程序不需要处理数据, 而仅仅只是做数据转移的时候, 程序buffer则会成为不必要的开销.

上面会涉及到多次上下文切换以及多次数据拷贝, 很大一部分cpu及内存开销是可以避免的, 于是有了zerocopy技术.

ZeroCopy

zerocopy技术省去了将操作系统的read buffer拷贝到程序的buffer, 以及从程序buffer拷贝到socket buffer的步骤, 直接将 read buffer 拷贝到 socket buffer. java 的 FileChannel.transferTo() 方法就是这样的实现, 这个实现是依赖于操作系统底层的sendFile()实现的.

public void transferTo(long position, long count, WritableByteChannel target);

他的底层调用的是系统调用sendFile()方法

#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

如下图

这样, 省去了两次buffer的copy, 并且上下文切换降到了2次(调用transferTo()进入内核态, 调用完毕返回用户态)

Linux 2.4 及以后的内核, 又做了改进, 不再使用socket buffer, 而是直接将read buffer数据拷贝到协议引擎, 而socket buffer只会记录数据位置的描述符和数据长度,如下

Zero Copy的更多相关文章

  1. HEC-ResSim原文档

              HEC-ResSim Reservoir System Simulation             User's Manual       Version 3.1 May 201 ...

  2. 关于ubuntu实机与虚机互相copy

    我的开发环境是在ubuntu上的,但是ubuntu上没有官方支持的QQ,有些不太方便,所以在上面虚了一个Win7(先是win10,但是win10最新版本太坑了,不说了),不过经常会出现复制文件,或者文 ...

  3. 探究@property申明对象属性时copy与strong的区别

    一.问题来源 一直没有搞清楚NSString.NSArray.NSDictionary--属性描述关键字copy和strong的区别,看别人的项目中属性定义有的用copy,有的用strong.自己在开 ...

  4. copy()之绝版应用

    我选用了一个稍稍复杂一点的例子,它的大致功能是:从标准输入设备(一般是键盘)读入一些整型数据,然后对它们进行排序,最终将结果输出到标准输出设备(一般是显示器屏幕).这是一种典型的处理方式,程序本身具备 ...

  5. Marshal.Copy将指针拷贝给数组

    lpStatuss是一个UNITSTATUS*的指针类型实例,并包含SensorDust字段 //定义一个数组类型 byte[] SensorDust = new byte[30] //将指针类型拷贝 ...

  6. @property中的copy.strong.weak总结

    1.NSString类型的属性为什么用copy NSString类型的属性可以用strong修饰,但会造成一些问题,请看下面代码 #import "ViewController.h" ...

  7. block为什么用copy以及如何解决循环引用

    在完成项目期间,不可避免的会使用到block,因为block有着比delegate和notification可读性更高,而且看起来代码也会很简洁.于是在目前的项目中大量的使用block. 之前给大家介 ...

  8. [LeetCode] Copy List with Random Pointer 拷贝带有随机指针的链表

    A linked list is given such that each node contains an additional random pointer which could point t ...

  9. NSString属性什么时候用copy,什么时候用strong?

           我们在声明一个NSString属性时,对于其内存相关特性,通常有两种选择(基于ARC环境):strong与copy.那这两者有什么区别呢?什么时候该用strong,什么时候该用copy呢 ...

  10. iOS 浅谈:深.浅拷贝与copy.strong

    深.浅拷贝 copy mutableCopy NSString NSString *string = @"汉斯哈哈哈"; // 没有产生新对象 NSString *copyStri ...

随机推荐

  1. ActiveMQ: 搭建Broker集群(cluster)

    上一篇介绍了基于Networks of Borkers的2节点HA方案,这一篇继续来折腾Networks of Brokers,当应用规模日渐增长时,2节点的broker可能仍然抗不住访问压力,这时候 ...

  2. [转载] Windows + IIS + PHP 配置

    资源下载: 下载windwos版本的PHP:http://windows.php.net/download/ (我下载的是PHP5.4.9_VC9 x86 Non Thread Safe,下载地址:h ...

  3. Git 实战教程

    CVS及SVN都是集中式的版本控制系统,而Git是分布式版本控制系统,集中式和分布式版本控制系统有什么区别呢? 先说集中式版本控制系统,版本库是集中存放在中央服务器的,而大家工作的时候,用的都是自己的 ...

  4. Linux下查看系统版本号信息的方法(转)

    一.查看Linux内核版本命令: 1.cat /proc/version [root@localhost ~]# cat /proc/versionLinux version 2.6.18-194.8 ...

  5. 制作U盘启动盘及安装操作系统的方法

    U盘启动盘制作方法: 1.从网上下载最新的老毛桃U盘启动制作工具主程序并安装 2.插入U盘(制作启动盘前先保存好你的资料到其它地方,以防丢失不可找回) 3.插入正确的U盘后程序会自动检测到U盘,启动模 ...

  6. python的paramiko源码修改了一下,写了个操作命令的日志审计 bug修改

    python的paramiko源码修改了一下,写了个操作命令的日志审计,但是记录的日志中也将backspace删除键记录成^H这个了,于是改了一下代码,用字符串的特性. 字符串具有列表的特性 > ...

  7. Dijkstar算法的数学原理

    Dijkstar算法是荷兰数学家迪克斯屈拉(or迪杰斯特拉?)在1959年发现的一个算法.是现有的几个求带权图中两个顶点之间最短通路的算法之一.算是一个相当经典的算法了. 迪克斯屈拉算法应用于无向连通 ...

  8. eclipse +VISUALSVN SERVER 创建版本控制器,防止误操作(可视化操作,简单方便,不需要修改配置文件)

    第一步:为eclipse安装Subclipse插件 打开eclipse,点击help-->Install New Software...弹出对话框,点击Add..(新增),以http://sub ...

  9. 总结一下在ASP.NET中开发网站的一般步骤

    1.打开Miscosoft Visual Studio2010 2.新建网页添加新项 3.设计网页 4.添加窗体控件 5.优化页面 6.调试网页

  10. jquery mobile界面数据刷新

    JQM里面当我们更新了某些页面标签(如: listview, radiobuttons, checkboxes, select menus)里的数据时,必须做refresh操作. 为什么必须做refr ...