0

0

了解Linux 和 Java 的零拷贝

coldplay.xixi

coldplay.xixi

发布时间:2020-07-01 17:41:12

|

2946人浏览过

|

来源于learnku

转载

了解Linux 和 Java 的零拷贝

Linux传统IO

大家好,我是一段躺在linux磁盘上的数据。现在要把我从磁盘发到网卡,需要经过以下步骤:

读操作

读操作

如上图:操作系统把内存分为了内核空间和用户空间。首先位于用户空间的应用程序使用发起数据读操作,比如JVM发起read()系统调用。这个时候操作系统会进行一次上下文切换:从用户空间切换到内核空间。

然后内核空间通知磁盘,内核把我从磁盘copy到内核缓冲区。这个过程是由一个叫“DMA(Direct memory access)”的硬件来做的,所以不需要CPU的参与。

然后内核把我从内核缓冲区copy到应用程序缓冲区,这里需要CPU的参与。

立即学习Java免费学习笔记(深入)”;

最后进行上下文切换,又换回到用户空间的上下文。

整个读操作的过程需要两次上下文切换和两次copy

相关学习推荐:Java视频教程

写操作

写操作与读操作类似,只是方向相反而已,仍然需要两次上下文切换和两次数据的copy。我可能会被写到磁盘,也可能会被写到网卡。

写操作

内存映射

从上面的过程可以看到,如果想把我从磁盘发送到网卡,需要总共4次上下文切换和4次copy操作。我被操作系统在内核空间和用户空间之间来回复制,但其实我在这期间什么也没有做,什么也没有变化,就是复制而已,所以这个IO模型太浪费操作系统资源了,我被复制这么多次,身心疲惫。而且操作系统的资源是非常宝贵滴~

现在主流的操作系统都使用了虚拟内存。简单来说,就是用虚拟地址取代物理地址,这样做可以让多个虚拟内存只想同一个物理地址,虚拟内存的空间可以远远大于物理内存的空间。

那如果操作系统能够把用户空间的应用程序缓冲区和内核空间的内核缓冲区映射到同一个物理地址,那岂不是就少了很多复制的过程?如下图:

内存映射

Linux零拷贝

所以为了解决这个问题,聪明的Linux开发者们写了一些新的系统调用来做这个事。主要有两种方式:

  • mmap + write
  • sendfile

mmap + write

mmap()系统调用首先会使用DMA copy的方式将我从磁盘读取到内核缓冲区,然后通过内存映射的方式,使用户缓冲区和内核读缓冲区的内存地址为同一内存地址,也就是说,不需要CPU再将我从内核读缓冲区复制到用户缓冲区啦!

当使用write()系统调用的时候,CPU将我从内核缓冲区(等同于用户缓冲区)直接写入到需要发送的内核缓冲区,比如网络发送缓冲区(socket buffer),然后通过DMA的方式将我传入到网卡驱动程序(或磁盘)中准备发送。

mmap + write

mmap + write的方式读写数据总共需要两次系统调用,4次上下文切换,2次DMA Copy和1次CPU Copy。

sendfile

sendfile也是一个系统调用,它其实本质上就是把上述两个系统调用的功能合起来,变成了一个调用。这样做的好处是,操作系统只需要2次上下文切换了,减少了2次上下文切换的开销。

ImgGood
ImgGood

免费在线AI照片编辑器

下载

gather

Linux2.4内核对sendfile进行了优化,提供了gather操作,这个操作可以把上图中的最后一次CPU copy去掉,原理就是不复制数据,而是把数据在之前的内核缓冲区(比如图中的案例是Read Buffer)的内存地址、偏移量记录发送给目标内核缓冲区(比如图中案例的Socket Buffer),这样在最后的DMA copy阶段就可以拿着这个指针直接去找数据copy了。

gather

Java NIO使用零拷贝

Linux的零拷贝确实能够节约一些操作系统的资源。所以Java的NIO为了支持零拷贝,提供了一些类:

  • DirectByteBuffer
  • FileChannel

在之前的《Java NIO - Buffer》这篇文章里大概介绍了DirectByteBuffer。ByteBuffer主要有两种实现,一种是DirectByteBuffer, 一种是HeapByteBuffer。

其中,DirectByteBuffer直接在堆外分配内存,底层是直接通过JNI调用操作系统的NIO系统调用,所以性能会比较高。而HeapByteBuffer是堆内内存,而且数据需要多一次拷贝,所以性能比较低。

FileChannel是Java NIO提供的用于复制文件的类,可以把文件复制到磁盘或者网络等。

map方法其实就是采用了操作系统中的内存映射方式,将内核缓冲区的内存和用户缓冲区的内存做了一个地址映射。

transferTo方法直接将当前通道内容传输到另一个通道,也就是说这种方式不会有内核缓冲区到用户缓冲区的读写问题。底层是sendfile系统调用。transferFrom方法同理。

示例代码:

File file = new File("test.txt");RandomAccessFile raf = new RandomAccessFile(file, "rw");FileChannel fileChannel = raf.getChannel();SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("", 8080));// 直接使用了transferTo()进行通道间的数据传输fileChannel.transferTo(0, fileChannel.size(), socketChannel);

作者:公众号_xy的技术圈

链接:www.imooc.com/article/289550

来源:慕课网

以上内容来自幕课网

零拷贝的再次理解

  1. 零拷贝,是从操作系统的角度来说的。因为内核缓冲区之间,没有数据是重复的(只有 kernel buffer 有一份数据)。

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

mmap和sendFile的区别

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

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

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

相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
java
java

Java是一个通用术语,用于表示Java软件及其组件,包括“Java运行时环境 (JRE)”、“Java虚拟机 (JVM)”以及“插件”。php中文网还为大家带了Java相关下载资源、相关课程以及相关文章等内容,供大家免费下载使用。

832

2023.06.15

java正则表达式语法
java正则表达式语法

java正则表达式语法是一种模式匹配工具,它非常有用,可以在处理文本和字符串时快速地查找、替换、验证和提取特定的模式和数据。本专题提供java正则表达式语法的相关文章、下载和专题,供大家免费下载体验。

738

2023.07.05

java自学难吗
java自学难吗

Java自学并不难。Java语言相对于其他一些编程语言而言,有着较为简洁和易读的语法,本专题为大家提供java自学难吗相关的文章,大家可以免费体验。

734

2023.07.31

java配置jdk环境变量
java配置jdk环境变量

Java是一种广泛使用的高级编程语言,用于开发各种类型的应用程序。为了能够在计算机上正确运行和编译Java代码,需要正确配置Java Development Kit(JDK)环境变量。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

397

2023.08.01

java保留两位小数
java保留两位小数

Java是一种广泛应用于编程领域的高级编程语言。在Java中,保留两位小数是指在进行数值计算或输出时,限制小数部分只有两位有效数字,并将多余的位数进行四舍五入或截取。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

398

2023.08.02

java基本数据类型
java基本数据类型

java基本数据类型有:1、byte;2、short;3、int;4、long;5、float;6、double;7、char;8、boolean。本专题为大家提供java基本数据类型的相关的文章、下载、课程内容,供大家免费下载体验。

446

2023.08.02

java有什么用
java有什么用

java可以开发应用程序、移动应用、Web应用、企业级应用、嵌入式系统等方面。本专题为大家提供java有什么用的相关的文章、下载、课程内容,供大家免费下载体验。

430

2023.08.02

java在线网站
java在线网站

Java在线网站是指提供Java编程学习、实践和交流平台的网络服务。近年来,随着Java语言在软件开发领域的广泛应用,越来越多的人对Java编程感兴趣,并希望能够通过在线网站来学习和提高自己的Java编程技能。php中文网给大家带来了相关的视频、教程以及文章,欢迎大家前来学习阅读和下载。

16925

2023.08.03

Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.2万人学习

Git 教程
Git 教程

共21课时 | 2.7万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号