【netty系列-05】深入理解直接内存与零拷贝

Netty系列整体栏目


内容链接地址
【一】深入理解网络通信基本原理和tcp/ip协议https://zhenghuisheng.blog.csdn.net/article/details/136359640
【二】深入理解Socket本质和BIOhttps://zhenghuisheng.blog.csdn.net/article/details/136549478
【三】深入理解NIO的基本原理和底层实现https://zhenghuisheng.blog.csdn.net/article/details/138451491
【四】深入理解反应堆模式的种类和具体实现https://zhenghuisheng.blog.csdn.net/article/details/140113199
【五】深入理解直接内存与零拷贝https://zhenghuisheng.blog.csdn.net/article/details/140721001

深入理解直接内存与零拷贝

  • 一,Nio直接内存与零拷贝
    • 1,堆内存和直接内存
      • 1.1,直接内存比堆内存快的原因
      • 1.2,直接内存使用的缺陷
    • 2,零拷贝
      • 2.1,Linux DMA
      • 2.2,传统的数据传输
      • 2.3,零拷贝-mmap内存映射
      • 2.4,零拷贝-sendfile
      • 2.5,零拷贝-splice
    • 3,java中使用的零拷贝

一,Nio直接内存与零拷贝

在该系列的第一片文章中,讲解了tcp的基本原理以及实现,在tcp的三次握手中,需要客户端先发起请求给服务端,然后客户端先发送一个 syn 等于1的标志,以及携带一个 seq_no 的序列号给服务端,从而完成第一次握手等等,然而根据tcp的特性,具有 网络重传 ,应答确认功能和封装报文 等功能时如何实现的呢,那么就是通过这个buffer缓冲区 实现的。

操作系统将tcp层以下的协议全部封装,然后通过调用操作系统的socket实现服务端与客户端之间的通信,因此需要通过socket去读取buffer缓冲区中的数据。这里的缓冲区指的是服务端内部之间的缓冲区,和前面提到的反应堆模式中的缓冲区不是同一个,这个缓冲区属于是业务缓冲区

请添加图片描述

1,堆内存和直接内存

通过上图可以得知,客户端在往对端发送数据时,需要先建立socket,然后通过buffer输入缓冲区和输出缓冲区,将数据发送给对端,发送数据的内部细节已由操作系统内部封装。

如在发送数据时,首选需要在用户态中,将数据加载到应用进程的缓冲区中,然后通过Socket建立连接,再调用操作系统的 write 相关的api,然后再将数据发送给内核态的 套接字发送缓冲区 里面,然后再通过一些tcp等协议栈,通过层层协议,通过网络、光缆等将数据发送给对端

请添加图片描述

1.1,直接内存比堆内存快的原因

不管是任何编程语言,都要遵循上面的这套规则,包括java也是。在java中jvm的整体架构如下,可以发现只有堆内存来存储对象,因此一般通过堆内存来存储buffer中的缓存数据

img

但是即使是先使用堆内存来存储buffer中的数据,在jvm内部也做了优化,在上面的这些结构中,加一个 DMA(Direct Memory Access) ,即直接内存的区域,如果是先用堆内存先存数据,也会将堆内存的数据复制(拷贝)到直接内存中,然后再通过直接内存区域中的数据,发送到内核的缓冲区,再发送到对端中。

jvm中使用直接内存的原因如下,首先是由于堆内存中会gc操作,那么在涉及对象复制或者空间碎片化管理等的时候,会将对象的位置进行移动,比如原先在100号位置,在调用write操作的时候,操作系统默认就会去读取堆内存上100号位置的数据,但是如果在读的时候发生了gc,导致堆内存上的数据发生了移动,那么原先100号的数据被挪到了50号,那么就会导致读取不到数据,或者读取不是该读取的数据 ,因此jvm为了优化这个堆内存读取buffer数据会出错的缺陷,专门开辟了一个新的直接内存,用于存储buffer数据

因此在做网络通信的时候,优先将存储buffer的内存改使用直接内存存储,堆存储需要一个数据拷贝到直接内存的时间,而直接内存不需要,因此使用直接内存是快于堆内存的。

1.2,直接内存使用的缺陷

在开发时直接使用直接内存确实爽,也可以加快整体效率,尤其时涉及到io密集型的操作时,可以显著的提升性能,但是使用直接内存也存在一些缺陷。

  • 如需要开发者手动的分配和释放内存,并且内存的开辟和释放不受jvm控制,也就是说内部需要涉及到底层系统的资源分配
//定义一个1m的直接内存
ByteBuffer allocate = ByteBuffer.allocate(1024 * 1024);
//直接内存空间释放
allocate.clear();
  • 其次就是如果内存不受jvm控制,那么调试会很困难,如一些内存泄漏无法保证,并且排查和调试这种问题也比较困难,一般的java监控工具都不能直接有效的监视直接内存的情况

  • 最后就是这个系统的资源利用率,由于并不受jvm控制,因此会增加操作系统的资源消耗,从而影响其他进程

因此开发者在考虑使用这个直接内存时,需要权衡利弊,结合实际的应用场景选择。

2,零拷贝

2.1,Linux DMA

在最早期的数据拷贝的方式如下,需要先通过cpu的介入,通过cpu的调度将磁盘加载到内存中,如需要从输入设备读取数据,然后将其写入内存。但是cpu主要做的大量的运算操作,如果让cpu长期的出去干这种没有含金量的事情,让cpu长时间的等待,会影响整个机器的性能,并且有损cpu的性能和价值,因此原始数据拷贝的方式相对较慢

为了解决上面的缺陷,减少cpu的负担,并且提高数据的传输效率,因此在硬件层面,就增加一块硬件,专门用于处理这种直接代替cpu去读取数据,加载内存,这个就叫做Linux的直接内存DMA。如增加一个磁盘驱动器,专门用于处理这种数据的读取和加载,而cpu就不需要像之前一样去调用输入输出设备,只需要给这个DMA发送一个指令即可,然后剩下的就交给DMA。DMA目前已经适用于多种计算机的硬件设备,如 硬盘驱动器、声卡、网络设备等

请添加图片描述

2.2,传统的数据传输

Linux在引入了DMA之后,系统可以更加的高速的对数据进行读写,并且可以高效的处理一些音频视频的数据。

在传统的数据传输引入了DMA之后,其数据传输效率更加高效,接下来如看一段简单的代码表示数据的读取和传输,就是先调用操作系统的api读取数据,然后将最终读取到的数据通过Socket发送到对端

//读取数据
FileBuffer buffer = new File.read()
//将数据发送到对端
Socket.send(buffer)    

上面这段代码虽然简单,但是在整个计算机内部执行的流程比较复杂,其主要流程如下:

  • 如在执行第一条语句的时候,此时还在用户态,通过程序计数器执行到改行代码,然后调用操作系统的api,此时需要将用户态切换为内核态,然后先从磁盘中将数据通过DMA的方式拷贝到文件读取的buffer缓冲区中,然后将文件缓冲区的数据投通过cpu拷贝到执行这条语句的jvm进程中,此时操作系统将内核态切换为用户态

  • 此时执行第二条语句,首先需要将进程中的数据通过CPU拷贝到Socket对应的buffer缓冲区中,又因为socket对应的send方法是操作系统层面的api,因此有需要从用户态切换到内核态,最后将socket中的buffer缓冲数据通过DMA拷贝的方式加入到网络设备对应的缓冲区中

请添加图片描述

总结来说就是需要4次用户态和内核态之间的上下文切换,4次数据的拷贝,分别是两次DMA拷贝,两次cpu拷贝。传统的数据传输虽然也是引入了DMA拷贝,但是依旧存在着两次CPU的拷贝,并且上下文切换也比较频繁

2.3,零拷贝-mmap内存映射

为了解决传统传输多次cpu拷贝带来的性能问题,在后面的优化中,采用了一种mmap内存映射的方式,就是提前对磁盘中数据的位置做一个映射,对应进程中的应用程序只需要通过这个地址直接去磁盘中拉取数据就行,从而不需要将数据先读取到buffer缓冲区中,同时也减少了一次cpu的拷贝

请添加图片描述

通过mmap的方式,减少了一次cpu的拷贝,因此只需要一次cpu拷贝,2次DMA拷贝,但是依旧需要4次上下文切换

2.4,零拷贝-sendfile

随着linux的不断升级,mmap的缺陷也在不断优化,在linux2.1的版本中,引入了sendfile的零拷贝方式,相对于mmap方式,sendfile同时在上下文切换和cpu拷贝时都做了优化。

从上下文切换来讲:

  • 在调用操作系统的read方法之后,其数据不需要再返回到用户态中,因此在整个传输流程结束之后再切换为用户态,因此在上下文切换只需要两次,比上面的减少了两次,剩下的两次上下文切换时必不可少的

从拷贝的角度来看:

  • 此时需要看该操作系统是否支持DMA拷贝,如果支持DMA拷贝,那么下图中的CPU拷贝可以直接不需要,就只需要两步:1、从磁盘中将数据通过DMA拷贝到文件缓冲区中,2、网络设备缓冲区直接读取文件缓冲区的数据 。此时只需要两次DMA拷贝,不需要CPU拷贝
  • 如果该操作系统不支持使用DMA拷贝,那么就需要一次CPU拷贝,流程如下:1、从磁盘中将数据通过DMA拷贝到文件缓冲区中,2、文件缓冲区的数据通过CPU拷贝到socket中的buffer缓冲区,3、网络设备缓冲区直接读取文件缓冲区的数据 。此时需要两次DMA拷贝,1次cpu拷贝

请添加图片描述

总结就是只需要两次上下文切换,两次DMA拷贝,0次或者1次的CPU拷贝

2.5,零拷贝-splice

在linux2.6版本中,又迎来了第三次优化,由于sendfile还需要根据特定的操作系统以及对应的环境才能不用cpu的拷贝,为了解决这种出现概率性的问题,因此splice出现了

其原理和sendfile很像,只是在文件缓冲区和socket缓冲区中加了一个管道,这就相当于把这两个东西合二为一了,也就相对于磁盘拷贝出去的区域和网络设备缓冲区拷贝进来的区域是同一个区域,因此在完全解决了不需要cpu拷贝。

请添加图片描述

相对于sendfile,这种零拷贝方式不会局限于某个操作系统或者环境,能保证不需要cpu拷贝,只需要两次上下文切换和两次DMA切换

3,java中使用的零拷贝

在java中,目前暂时没有支持splice方式的零拷贝,即目前只支持mmap方式和sendfile方式。在java的各个中间件中,如kafka,nio等等这些地方用到了零拷贝。kaka在生产者端使用的是mmap,结合顺序写可以每秒处理百万级别的业务,生产端使用的是sendfile。nio中在读取数据时也使用mmap,在数据传输中也用了sendfile方式

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/384295.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Spring MVC 应用分层

1. 类名使⽤⼤驼峰⻛格,但以下情形例外:DO/BO/DTO/VO/AO 2. ⽅法名、参数名、成员变量、局部变量统⼀使⽤⼩驼峰⻛格 3. 包名统⼀使⽤⼩写,点分隔符之间有且仅有⼀个⾃然语义的英语单词. 常⻅命名命名⻛格介绍 ⼤驼峰: 所有单词⾸字⺟…

探索Linux-1-虚拟机远程登陆XShell6远程传输文件Xftp6

Linux是什么? Linux是一个开源的操作系统内核,由林纳斯托瓦兹(Linus Torvalds)于1991年首次发布。它基于Unix操作系统,但提供了更多的自由和灵活性。Linux内核是操作系统的核心部分,负责管理系统资源、处理…

CSS:position属性

一、属性值 1.1 fixed 固定位置的元素,相对于浏览器窗口进行定位。 元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定。 网站中的固定 header 和 footer 就是用固定定位来实现的; header效果图 footer效果图 1.2 absol…

inxedu 因酷教育软件环境搭建

1 地址下载网校系统_考试系统_培训系统_直播教学系统_在线教育系统源码-因酷教育软件-北京因酷时代科技有限公司 2 在idea上的部署环境 解压后用idea打开 maven设置 java编辑器配置 将jdk设置为1.7 tomcat选择为7配置 数据库配置 修改cms上链接数据库的密码 修改端口 运行cms

可能是最好的工具网站

前些苏音在刷视频,发现了一堆好用的宝藏网站,这就赶快分享给大家。 工具网站 这个网站类似于网址导航,集合了包括工具类、资源类、软件类、AI类的合集 并且站长表示励志做体验感最好的工具网,聚焦最快解决用户的需求 首先就是办…

微信自动回复

微信自动回复 文章目录 微信自动回复自动回复步骤微信展开在微信消息区进行监测将微信聊天区截图回复信息实现多次回复(封装函数) 结语 嗨!收到一张超级美丽的风景图,愿你每天都能顺心! 我们这里主要使用pyautogui库&a…

百日筑基第二十八天-23种设计模式-行为型总汇

百日筑基第二十八天-23种设计模式-行为型总汇 文章目录 百日筑基第二十八天-23种设计模式-行为型总汇前言模板方法模式简介模板方式的特点模板方法模式结构类图模板方式模式案例分析模板方法模式应用源码分析模板方法模式的注意事项和细节 迭代器模式迭代器模式结构类图迭代器模…

MySQL 约束 (constraint)

文章目录 约束(constraint)列级约束和表级约束给约束起名字(constraint)非空约束(no null)检查约束(check)唯一性约束 (unique)主键约束 (primary key)主键分类单一主键复合主键主键自增 (auto_increment) 外键约束外什…

cpp程序设计实践,类实现树链刨分以及计算几何类

程序设计要求 是某个cq高校期末程序设计实践作业,全部自己做的比较小众分值90。  试建立一个继承结构,以栈、队列为派生类,建立它们的抽象基类-Bag类,写出各个类的声明及定义,并实现如下功能:  统一命名…

C++基础知识:函数重载相关注意事项:1.引用作为重载条件,2.2.函数重载遇见函数默认参数。

1.引用作为重载条件 #include<iostream>using namespace std;//1.引用作为重载的条件 //int 和 const int 类型不同&#xff0c;所以可以作用重载条件 void fn(int &a) //int &a10;不合法 //10放在了常量区&#xff0c;而引用要么在栈区&#xff0c;要么在堆区{…

【Python】sqlite加密库pysqlcipher3编译安装步骤

目录 说明准备工作openssl编译sqlitetcl setup.py修改quote_argumentopenssl路径 安装加密示例代码测试附录参考 说明 pysqlcipher3是针对Python 3使用的pysqlcipher的一个分支&#xff0c; 尽管仍然维护对Python 2的支持。它仍然处于测试阶段&#xff0c; 尽管这个库包含的最…

网络安全常见错误及解决办法(更新中)

# 开启代理&#xff0c;无法连接网络 把代理关掉 # 上一秒还在安装tree&#xff0c;下一秒xshell就连接不上了 —》sshd服务的key这个文件权限过高&#xff0c;跟装tree没有关系&#xff0c;装一个epel 源&#xff0c;epel-release​ 部分命令&#xff1a;chmod 600 /etc/ssh…

pikauchu之Unsafe Fileupload(不安全的文件上传)

Client check&#xff08;客户检查&#xff09; 第一步先新建一个一句话木马 <?php eval($_POST[1]);?> 然后上传文件 有限制&#xff0c;只能上传那几种类型 现在看看源代码 我们将一句话木马文件的后缀改为png 然后用burp抓包&#xff0c;将png改成php 就能上传成功 …

Android Studio导入源码

在有源码并且编译环境可用的情况下&#xff1a; 1.生成导入AS所需的配置文件 在源码的根目录执行以下命令&#xff1a; source build/ensetup.sh lunch 要编译的项目 make idegen //这一步会生成out/host/linux-x86/framework/idegen.jar development/tools/idegen/idegen.sh…

Spring Boot集成canal快速入门demo

1.什么是canal&#xff1f; canal 是阿里开源的一款 MySQL 数据库增量日志解析工具&#xff0c;提供增量数据订阅和消费。 工作原理 MySQL主备复制原理 MySQL master 将数据变更写入二进制日志&#xff08;binary log&#xff09;, 日志中的记录叫做二进制日志事件&#xff…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第五十七章 Linux中断实验

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

Spring AI (三) 提示词对象Prompt

3.提示词对象Prompt 3.1.Prompt Prompt类的作用是创建结构化提示词, 实现了ModelRequest<List<Message>>接口 Prompt(String contents)&#xff1a;创建一个包含指定内容的Prompt对象。 Prompt(String contents, ChatOptions modelOptions)&#xff1a;创建一个…

基于Qt的上位机通用框架

0.前言 最近一年多的时间一直在开发设备控制相关的软件&#xff0c;加上之前在聚光的两年时间&#xff0c;前前后后开发这种设备控制类型的上位机软件也有三年的时间了。总结出了一套基于Qt的上位机编程框架&#xff0c;核心思想类似于C#的依赖注入&#xff0c;对象的初始化都…

java计算机毕设课设—记账管理系统(附源码和安装视频)

这是什么系统&#xff1f; java计算机毕设课设—记账管理系统&#xff08;附源码和安装视频&#xff09; 记账管理系统主要用于财务人员可以从账务中判断公司的发展方向。对个人和家庭而言&#xff0c;通过记账可以制定日后的 消费计划&#xff0c;这样才能为理财划出清晰合理…

ATF-541M4全解析(一)

目录 一、描述二、规格三、各参数最大值四、25℃下的典型值 一、描述 安华高科技 (Avago Technologies) 的 ATF-541M4 是一款高线性度、低噪声、单电源供电的E-PHEMT&#xff0c;封装在一个微型无引脚封装中。 ATF-541M4 的小尺寸和低外形使其非常适合用于混合模块和其他空间…