原文出处: 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. IOS第11天(1:UIPickerView点餐)

    UIPickerView #import "ViewController.h" @interface ViewController ()<UIPickerViewDataSo ...

  2. getServletPath getRequestURI getRequestURL区别

    getContextPath:/test               //上下文,类似工程名 getServletPath:/test.jsp getRequestURI:/test/test.jsp ...

  3. Linux 安装pip

    参考:为Linux 系统安装pip pip: "A tool for installing and managing Python packages.",也就是说pip是pytho ...

  4. 现在写 PHP,你应该知道这些

    现在写 PHP,你应该知道这些 2015-10-21    分类:WEB开发.编程开发.首页精华2人评论     来源:Scholer's Blog 分享到:更多3 二十万年薪PHP工程师培养计划 成 ...

  5. jquery 判断时间

    $("#gjlycon1").blur(function () {                 var v = $(this).val();                 v ...

  6. Pivot C# WPF 代码添加PivotItem

    PivotItem new_PivotItem = new PivotItem();//新建Pivotitem ListView new_ListView = new ListView();//新建l ...

  7. LeetCode Palindrome Permutation II

    原题链接在这里:https://leetcode.com/problems/palindrome-permutation-ii/ 题目: Given a string s, return all th ...

  8. Android利用canvas画各种图形(点、直线、弧、圆、椭圆、文字、矩形、多边形、曲线、圆角矩形) .

    1.首先说一下canvas类: Class Overview The Canvas class holds the "draw" calls. To draw something, ...

  9. EF CodeFirst 创建数据库

    最近悟出来一个道理,在这儿分享给大家:学历代表你的过去,能力代表你的现在,学习代表你的将来. 十年河东十年河西,莫欺少年穷 学无止境,精益求精    话说EF支持三种模式:Code First   M ...

  10. url.py中的配置问题

    urlpatterns = [    url(r'^add$', calc_views.add, name='add'),      url(r'^admin/', admin.site.urls), ...