原文出处: 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. 使用eclipse开发servlet

    package cn.itcast; import java.io.IOException; import javax.servlet.GenericServlet; import javax.ser ...

  2. shader三种变量类型(uniform,attribute和varying)

    uniform变量在vertex和fragment两者之间声明方式完全一样,则它可以在vertex和fragment共享使用.(相当于一个被vertex和fragment shader共享的全局变量) ...

  3. php的字符串处理函数

    Strpos($str,”img”); //返回字符串的位置 Substr($str,int start,int length); 使用这两个函数可以截取字符串

  4. ThinkPHP 3.2.3 URL 路由的使用

    ThinkPHP3.2.3 手册中路由的地址是: http://www.kancloud.cn/manual/thinkphp/1706 简单配置实例:在配置文件 config.php 中添加 //路 ...

  5. 台式机的集显HD4600驱动-黑苹果之路

    台式机的集显HD4600驱动-黑苹果之路 半桶水还真可怕,整了一个礼拜的台式机黑苹果,竟然都没搞定asus z87-k的HD4600核显.最终为了不耽误工作,上淘宝,花钱买服务.显卡驱动分为变色龙和c ...

  6. 正则基础之——捕获组(capture group)

    1        概述 1.1     什么是捕获组 捕获组就是把正则表达式中子表达式匹配的内容,保存到内存中以数字编号或显式命名的组里,方便后面引用.当然,这种引用既可以是在正则表达式内部,也可以是 ...

  7. 程序最多能new多少内存(2G内存里要放程序的5大区,HeapAlloc比new要快多了,而且超过2G的时候会告诉你)

    根据<Windows核心编程>得知:X86操作系统提供每个程序最多只有4G的虚拟内存,其中2G虚拟内存提供给系统用(具体用来干什么还待考察),还有2G的内存留给用户使用.那这2G内存能拿来 ...

  8. MySql注入科普

    默认存在的数据库: mysql 需要root权限读取 information_schema 在5以上的版本中存在 测试是否存在注入方法 假:表示查询是错误的 (MySQL 报错/返回页面与原来不同) ...

  9. nginx执行文件替换掉之后重启提示permission denied

    重启的时候显示 -bash: /usr/local/nginx/sbin/nginx: Permission denied 进入nginx执行文件的目录:

  10. iOS,Xcod7/8,iOS使用修改点

    1.Xcod7使用修改点 2.Xcode8使用修改点 Xcod7使用修改点 1.xcode7 新建的项目,Foundation下默认所有http请求都被改为https请求. HTTP+SSL/TLS+ ...