进程间通信之共享内存分析

2023-11-16

零拷贝技术:https://strikefreedom.top/linux-io-and-zero-copy

一、内存映射和共享内存的区别

1.1、内存映射之mmap函数:将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存,而系统会自动回写脏页面到对应的文件磁盘上,即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间,从而可以实现不同进程间的文件共享。需要注意的是在mmap之后,并没有在将文件内容加载到物理页上,只上在虚拟内存中分配了地址空间。当进程在访问这段地址时(通过mmap在写入或读取时FileA),若虚拟内存对应的page没有在物理内存中缓存,则产生"缺页",由内核的缺页异常处理程序处理,将文件对应内容,以页为单位(4096)加载到物理内存。

void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);
参数:

start:指向欲映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。

length:代表将文件中多大的部分映射到内存。

prot:映射区域的保护方式。可以为以下几种方式的组合:

  • PROT_EXEC 映射区域可被执行
  • PROT_READ 映射区域可被读取
  • PROT_WRITE 映射区域可被写入
  • PROT_NONE 映射区域不能存取

flags:影响映射区域的各种特性。在调用mmap()时必须要指定MAP_SHARED 或MAP_PRIVATE。

  • MAP_FIXED 如果参数start所指的地址无法成功建立映射时,则放弃映射,不对地址做修正。通常不鼓励用此旗标。
  • MAP_SHARED:对映射区域的写入数据会复制回文件内, 而且允许其他映射该文件的进程共享。 与其它所有映射这个对象的进程共享映射空间,对共享区的写入,相当于输出到文件。
  • MAP_PRIVATE 对映射区域的写入操作会产生一个映射文件的复制,即私人的“写入时复制”(copy on write)对此区域作的任何修改都不会写回原来的文件内容。
  • MAP_ANONYMOUS建立匿名映射。此时会忽略参数fd,不涉及文件,所以映射区域无法和非亲缘进程共享。
  • MAP_DENYWRITE只允许对映射区域的写入操作,其他对文件直接写入的操作将会被拒绝。
  • MAP_LOCKED 将映射区域锁定住,这表示该区域不会被置换(swap)。

fd:要映射到内存中的文件描述符。如果使用匿名内存映射时,即flags中设置了MAP_ANONYMOUS,fd设为-1。有些系统不支持匿名内存映射,则可以使用fopen打开/dev/zero文件,然后对该文件进行映射,可以同样达到匿名内存映射的效果。

offset:文件映射的偏移量,通常设置为0,代表从文件最前方开始对应,offset必须是分页大小的整数倍。

返回值:若映射成功则返回映射区的内存起始地址,否则返回MAP_FAILED(-1),错误原因存于errno 中。

1.2、IPC之共享内存

共享内存是在两个正在运行的进程间共享和传递数据的一种高效形式。不同进程之间共享的内存通常安排在同一段物理内存中。进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址。IPC共享内存的实现借用了mmap机制。共享内存是最快的进程间通信方式。共享内存并未提供同步机制,也就是说,在第一个进程结束对共享内存的写操作之前,并无自动机制可以阻止第二个进程开始对它进行读写。所以我们通常需要同步机制控制对共享内存的访问,比如信号量 。

  • Posix接口,共享内存的POSIX接口,使用方法:shm_open()、mmap()。POSIX的共享内存实现会默认把共享内存文件放在/dev/shm/分区下,如果没有这个分区,需要手动挂载一下。POSIX共享内存一般要放在/dev/shm/目录下,这是因为/dev/shm/使用了一种特殊的文件系统tmpfs,它是虚拟的,并不是磁盘上的真实的分区,速度较快,性能较好。Linux共享内存的实现依赖于共享内存文件系统,该文件系统通常装载在/dev/shm,在调用shm_open系统函数的时候,会在/dev/shm/目录下生成内存文件。

    shm_open:创建一个新的共享区域或者附加在已有的共享区域上.区域被其名字标识,函数返回各文件的描述符.
    
    shm_unlink:类似于unlink系统调用对文件进行操作,直到所有的进程不再引用该内存区后才对其进行释放.
    
    mmap:用于将一个文件映射到某一内存区中,其中也使用了shm_open函数返回的文件描述符.
    
    munmap:用于释放mmap所映射的内存区域.
    
    msync:同步存取一个映射区域并将高速缓存的数据回写到物理内存中,以便其他进程可以监听这些改变.
    
  • System V接口,使用方法shmget()、shmmat()…

    shmget:创建一个新的共享区域或者附加在已有的共享区域上(同shm_open).
    
    shmat:用于将一个文件映射到内存区域中(同mmap).
    
    shmdt:用于释放所映射的内存区域(同munmap)
    
    shmctl:对于多个用户,断开其对共享区域的连接(同shm_unlink)
    

1.3、共享内存和直接文件内存映射(mmap)的区别?

​ 共享内存和文件内存映射的接口、用法不一样,POSIX的共享内存实现会默认把共享内存文件放在/dev/shm/分区下,如果没有这个分区,需要手动挂载一下。直接内存映射的文件无关文件的位置。然后就是共享内存和文件内存映射,在内核中的实现原理,都使用了内核的cache和swap机制,完全没有区别。

1.4、共享内存和read/write相比优缺点是什么?

直接将文件映射到虚拟内存,意味着没有数据没有缓存在内核缓存空间,而是直接读到了用户空间,回想一下系统的IO和内核缓存搭配可以使得部分的文件使用效率更高。(因为OS会根据局部性原理在一次read()系统调用的时候预读取更多的文件数据到内核空间缓冲区中,这样当下一次read()系统调用的时候发现要读取的数据已经存在于内核空间缓冲区中的时候只要直接拷贝数据到用户空间缓冲区中即可,无需再进行一次低效的磁盘I/O操作)。而且从mmap的细节我们可以看到,mmap映射区域大小必须是物理页大小(page_size)的整倍数(32位系统中通常是4k字节)。原因是内存的最小粒度是页,而进程虚拟地址空间和内存的映射也是以页为单位。为了匹配内存的操作,mmap从磁盘到虚拟地址空间的映射也必须是页。映射的文件最好是大于4k的(一个内存页的大小),并且最好是4k的倍数。也就是说两个方式都是有优缺点的,只能通过分析其场景而选择不同的方式。


二、多进程间(亲缘进程和非亲缘进程间)使用mmap的共享内存(与磁盘同步):

在这里插入图片描述

2.1、mmap匿名映射。

既然是兄弟,或者父子进程间进行通信,我们有着一样的数据,为什么一定要靠着打开一个文件,然后映射到内存,来进行通信呢?它们之间也不需要被映射到内存中的文件中的数据呀,这样做是是不是多此一举?于是就想我们可以请求操作系统在内存中,给他们开辟一块固定大小的空间,它们使用这块内存的地址,来作为桥梁进行通信,这就是匿名内存映射区

void *mptr = mmap(NULL,len,PROT_READ | PROT_WRITE,MAP_SHARED | MAP_ANON,-1,offset);
//注意
mode参数必须要有一个参数是 MAP_ANON
文件描述符可以填-1
len 长度需要指定出来,4k的整数倍

2.2、mmap映射共有四种组合, 私有/共享、文件/匿名映射组合。

  • 私有文件映射:多个进程使用同样的物理页面进行初始化,但是各个进程对内存文件的修改不会共享,也不会反映到物理文件中。

比如对linux .so动态库文件就采用这种方式映射到各个进程虚拟地址空间中。

  • 私有匿名映射:mmap会创建一个新的映射,各个进程不共享,主要用于分配内存(malloc分配大内存会调用mmap)。

  • 共享文件映射:多个进程通过虚拟内存技术共享同样物理内存,对内存文件的修改会反应到实际物理内存中,也是进程间通信的一种。

  • 共享匿名映射:这种机制在进行fork时不会采用写时复制,父子进程完全共享同样的物理内存页,也就是父子进程通信。

2.3、系统调用mmap用于共享内存时有下面两种常用的方式: 对于任意的两个进程可以使用第一种方式,而对于具有亲缘关系的进程实现共享内存最好的方式应该是采用匿名内存映射的方式.此时,不必指定具体的文件,只要设定相应的标志即可

  • 使用普通文件提供的内存映射:适用于任何进程之间.此时,需要打开或创建一个文件,然后再调用mmap, 常见于非亲缘进程之间的共享内存通信。
  • 使用特殊文件提供的匿名内存映射:适用于具有亲缘关系的进程之间.由于父子进程特殊的亲缘关系,在父进程中调用mmap,然后调用fork.那么在调用fork之后,子进程会继承父进程匿名映射后的地址空间,同样也继承mmap返回的地址,这样,父子进程就可以通过映射区进行通信了。注意,mmap返回的地址,需要由父子进程共同维护。

三、pod共享内存

3.1、pod内的多容器通信

​ 同一pod下的容器使用相同的网络名称空间,这就意味着他们可以通过’localhost’来进行通信,它们共享同一个Ip和相同的端口空间

​ 同一个pod里的容器共享IPC名称空间,这就意味着他们可以通过进程间通信的手段来进行通信。kubernetes创建的Pod,其共享内存默认64MB,且不可更改。kubernetes本身是没有设置share memory的大小的,64MB其实是docker 默认的共享内存的大小。docker run 的时候,可以通过--shm-size来设置共享内存的大小。k8s可以将memory类型的emptyDir挂载到/dev/shm来解决共享内存大小的问题。

​ 可以使用一个共享的存储卷来简单高效的地在容器间共享数据.大多数情况下,使用一个共享目录在同一pod里的不同容器间共享数据就够了。在Pod的不同container之间需要共享数据,可以将同一个emptyDir挂载到两个container中来达到共享的目的。此时,emtpyDir实际是一个宿主机上的目录,本质上还是磁盘(比如通过sidecar的方式来收集日志)。kubernetes提供来一种特殊的emptyDir:medium为memory的临时存储。用户可以将memory介质的emptyDir挂到任何目录,然后将这个目录当作一个高性能的文件系统来使用。emptyDir支持Memory,可以将该emptyDir.medium字段设置"Memory" 告诉Kubernetes安装tmpfs(RAM支持的文件系统),配合deploy,可以实现在pod使用共享内存超出限制的时候驱逐pod。

spec:
      containers:
      - image: centos:7
        name: centos
        volumeMounts:
        - mountPath: /dev/shm
          name: cache-volume
      volumes:
      - emptyDir:
          medium: Memory
          sizeLimit: 128Mi
        name: cache-volume

3.2 、pod间共享内存

同一个Node上不同的Pod之间若使用共享内存通信,则需要使用主机路径的挂载卷。

     containers:
      - name: demo-agent
        image: demo_agent:1.0
        volumeMounts:
        - mountPath: /dev/shm
          name: shm
        resources:
          limits:
            cpu: 200m
            memory: 200Mi
          requests:
            cpu: 100m
            memory: 100Mi
      volumes:
      - name: shm
        hostPath:
          path: /dev/shm
          type: Directory

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

进程间通信之共享内存分析 的相关文章

  • 内存管理之一__align字节对齐

    转 http www cnblogs com ye moooooo p 4601189 html 一 什么是字节对齐 为什么要对齐 现代计算机中内存空间都是按照byte划分的 从理论上讲似乎对任何类型的变量的访问可以从任何地址开始 但实际情
  • libevent(6)windows上使用iocp网络模型

    windows操作系统上不能使用epoll模型 只能使用iocp网络模型 这里我把怎么在windows上使用iocp的代码直接贴上 include
  • 案例——UDP聊天

    UDP聊天案例 做一个网络编程相关的案例 想着用利用UDP的快速且不用连接的优点做一个聊天室 我们一个聊天程序需要可以接收消息 也要可以发送消息 所以我们的DatagramSocket对象不但需要调用send函数 还需要调用recieve函
  • 【Python爬虫与数据分析】爬虫Json数据解析

    目录 一 Json文件数据解析 二 Json数据包解析获取图片资源 三 Json数据包解析获取视频资源 一 Json文件数据解析 json字符串 通常类似python数据类型中的列表和字典的结合 也可能是单独的列表或者字典格式 通常可以通过
  • 回调函数

    单线程的时候同步的话 很容易阻塞在那边 用户体验极差 例如 异步是可以多线程的 因为UI主线程一旦阻塞整个界面就卡死了 一旦异步 两个线程下一个可以后台处理数据 一个可以做UI显示 js是单线程的 如果所有的操作 ajax 获取文件等I O
  • libev学习系列之三:libev编译安装

    libev学习系列之三 libev编译安装 版本说明 版本 作者 日期 备注 0 1 ZY 2019 5 31 初稿 目录 文章目录 libev学习系列之三 libev编译安装 版本说明 目录 源码结构 正常编译 交叉编译 源码结构 4 2
  • LibEvent中文帮助文档

    http blog csdn net zhouyongku article details 53431597 libevent源码分析 http blog csdn net yusiguyuan article details 182675
  • 一看就懂的网络协议五层模型(一)

    我们每天使用互联网 你是否想过 它是如何实现的 全世界几十亿台电脑 连接在一起 两两通信 上海的某一块网卡送出信号 洛杉矶的另一块网卡居然就收到了 两者实际上根本不知道对方的物理位置 你不觉得这是很神奇的事情吗 互联网的核心是一系列协议 总
  • Netty聊天系统(1)通过自定义协议实现客户端与服务器端通信

    1 自定义实现客户端与服务器端通信的协议 1 1 通信协议的设计 自定义的通信协议需要哪些内容 1 魔数 第一个字段一般是魔数 一般固定的几个字节 一个PNG图片的编码中有固定数量固定内容的字节 用于表示这是一个PNG图片 Java的Cla
  • Ubuntu 下同局域网主机访问Tomcat 服务器

    转自 https blog csdn net zm yang article details 70483439 搭建Tomcat环境 自己写些小应用 需要用到服务器 便在Ubuntu环境下搭建了个Tomcat服务器 搭建方法很简单 去官网下
  • Unity使用C#实现简单Scoket连接及服务端与客户端通讯

    简介 网络编程是个很有意思的事情 偶然翻出来很久之前刚开始看Socket的时候写的一个实例 贴出来吧 Unity中实现简单的Socket连接 c 中提供了丰富的API 直接上代码 服务端代码 Thread connectThread 当前服
  • C# 序列化与反序列化几种格式的转换

    这里介绍了几种方式之间的序列化与反序列化之间的转换 首先介绍的如何序列化 将object对象序列化常见的两种方式即string和xml对象 第一种将object转换为string对象 这种比较简单没有什么可谈的 public string
  • 基于TCP的服务器端/客户端

    TCP服务器端默认函数调用顺序 socket 创建socket bind 分配socket地址 listen 等待连接请求状态 accept 允许连接 read write 数据交换 close 断开连接 等待连接请求状态 int list
  • 关于Socket编程中的inet_ntop、inet_pton和inet_ntoa、inet_addr

    VS2013中调试Socket代码时 遇到了点小问题 问题代码为 cpp view plain copy inet ntoa addrClient sin addr 生成错误消息为 plain view plain copy error C
  • C++知识分享: Socket 编程详解,万字长文

    介绍 Socket编程让你沮丧吗 从man pages中很难得到有用的信息吗 你想跟上时代去编Internet相关的程序 但是为你在调用 connect 前的bind 的结构而不知所措 等等 好在我已经将这些事完成了 我将和所有人共享我的知
  • 【系统】C/C++内存管理之内存分配

    文章目录 0 内存分配方式 从静态存储区域分配 在栈上创建 在堆上分配 程序内存空间 1 C语言内存分配方式 静态与动态内存分配区别 1 1 静态分配方式 1 2 动态分配方式 1 malloc函数 2 calloc 函数 3 reallo
  • fork()函数详解

    一个进程 包括代码 数据和分配给进程的资源 fork 函数通过系统调用创建一个与原来进程几乎完全相同的进程 也就是两个进程可以做完全相同的事 但如果初始参数或者传入的变量不同 两个进程也可以做不同的事 一个进程调用fork 函数后 系统先给
  • 为什么栈的数组长度必须是一个常量?而堆的数组长度可以是变量。为什么栈的大小有限制?

    为什么栈的数组长度必须是一个常量 而堆的数组长度可以是变量 栈区数组长度使用变量会报错 其原因就在于栈是编译器管理的 在程序运行前就已经分配好了空间的大小 而使用变量 编译器无法知道该分配多大的内存空间 于是报错 但堆上的内存是动态创建的
  • Go内存管理及性能观测工具

    内存管理 TCMalloc Golang内存分配算法主要源自Google的TCMalloc算法 TCMalloc将内存分成三层最外层Thread Cache 中间层Central Cache 最里层Page Heap Thread Cach
  • 使用epoll时需要将socket设为非阻塞吗?

    本文是回答一位知友的提问 在APUE中介绍select和poll中说 一个描述阻塞与否并不影响select是否阻塞 也就是说 如果希望读一个非阻塞描述符 并且以超时值5s调用select 则select最多阻塞5s 我看到有些程序使用epo

随机推荐

  • pgsql:远程连接时出现报错“发生致命错误:没有用于主机“…”,用户“…”,数据库“…”,SSL关闭的pg_hba.conf记录“,或者英文乱码

    问题 在用Navicat Premium远程连接pgsql时出现报错 发生致命错误 没有用于主机 用户 数据库 SSL关闭的pg hba conf记录 或者英文乱码 其实是与上述是同一个意思 解决方案 按提示找到pg安装目录下的 data
  • springboot 整合 redis

    springboot 整合 redis 1 导入依赖
  • {CTFshow} 萌新web1 详解

    练习ctf当然不止一个平台啦 所以我打算也写一写ctfshow的题目 好家伙 直接明了 就是让我审计代码 看完发现 我们要用get方式提交 flag在id 1000 但是直接提交id 1000会返回错误 所以我们需要再添加一个id用来防止被
  • springboot 访问远程服务器文件,springboot使用JSch远程读取sshd服务器上的文件

    JSch 是SSH2的一个纯Java实现 它允许你连接到一个sshd 服务器 使用端口转发 X11转发 文件传输等等 你可以将它的功能集成到你自己的 程序中 同时该项目也提供一个J2ME版本用来在手机上直连SSHD服务器 实现一个java工
  • 前后端分离ajax接收文件流的实践

    一般ajax post请求不能实现的原因 开始的想法 在页面上用jQuery的 post方法发送一个请求给服务器 然后服务器根据这个参数再生成相应的一个文件流返回给客户端 但是 在 post方法的回调函数中 只能处理xml json scr
  • 手机android端安装配置cpolar内网穿透

    cpolar作为一款强大的内网穿透工具 能够在不同操作系统平台中得到应用 真正打通了不同操作系统之间的围墙 让我们能方便的从一个操作平台中 读取到另一个操作平台中的数据 甚至对另一操作平台中运行的程序进行调试 今天 我们就为大家介绍 如何在
  • .Net Core缓存及问题规避

    目录 一 什么是缓存 二 客户端响应缓存 三 服务器端响应缓存 四 内存缓存 五 缓存穿透问题的规避 六 缓存雪崩问题的规避 七 缓存数据混乱的规避 八 分布式缓存 九 缓存方式的选择 一 什么是缓存 缓存是系统优化中简单又以有效的工具 只
  • 【C语言】小知识点

    Hello 各位小伙伴们 大家好啊 又和大家见面了 本期我会讲一点C语言的一些小知识点 希望大家可以学到有用的知识点哦 文章目录 Hello 各位小伙伴们 大家好啊 又和大家见面了 本期我会讲一点C语言的一些小知识点 希望大家可以学到有用的
  • "VT-x is disabled in BIOS"的解决办法

    当创建模拟器的时候发生了如下图的问题 解决办法 1 重启电脑 2 按F2进入BIOS 3 找到 Intel Virtual Technology 他这时会显示disable 按Enter把他改成enable即可 当时我在网页上寻找帮助时 好
  • 【华为OD机试真题】最左侧冗余覆盖子串(C++&java&python)100%通过率 超详细代码注释 代码优化

    华为OD机试真题 2022 2023 真题目录 点这里 华为OD机试真题 信号发射和接收 试读 点这里 华为OD机试真题 租车骑绿道 试读 点这里 最左侧冗余覆盖子串 知识点滑窗 时间限制 1s 空间限制 256MB 限定语言 不限 题目描
  • TinyML构建卷积神经网络(CNN)模型声控Arduino机器车

    本教程介绍了如何将机器学习与 Arduino 结合使用 在微控制器上运行由TinyML构建的机器学习语音识别模型 控制Arduino机器车运行 要构建这个项目 至少有两个步骤 训练一个新的机器学习模型并使其适应在 Arduino 上运行 使
  • visio连接线和框图不好控制总跑跳问题

    方法1 视图点右下角小箭头 点开后在常规一栏把对齐和粘附的勾去掉就可以了 方法2 点开始 在连接线旁边有个 X 号 点击X号后按ctrl就可以用鼠标在任意地方设置连接点
  • replace()和replaceAll()的区别

    replace char oldChar char newChar 返回一个新的字符串 它是通过用 newChar 替换此字符串中出现的所有 oldChar 而生成的 参数是字符串也成立 eg str replace 20 用 20 替换空
  • 狂神说SpringMVC 最全学习笔记

    SpringMVC 1 回顾MVC 1 1 什么是MVC MVC是模型 Model 视图 Views 控制器 Controller 得缩写 是一种软件设计规范 是将业务逻辑 数据 显示分离得方法组织代码 MVC主要作用是降低了视图与业务逻辑
  • npm run dev,npm run serve 运行到一半卡死

    Vue npm run dev npm run serve 运行到一半卡死 有两个原因会造成这个结果 modules中缺少依赖 使用npm install 命令重新加载依赖 Vue规定每个template中必须有一个根div 如果有两个di
  • 【雕爷学编程】Arduino 手册之比较运算符的成员运算符和非成员运算符

    什么是Arduino Arduino 是一款开源的电子原型平台 它可以让你用简单的硬件和软件来创建各种创意的项目 无论你是初学者还是专家 Arduino 都能为你提供无限的可能性 你可以用 Arduino 来控制传感器 灯光 马达 机器人
  • Qt学习11:Dialog对话框操作总结

    文章首发于我的个人博客 欢迎大佬们来逛逛 完整Qt学习项目地址 源码地址 文章目录 QDialog QDialogButtonBox QMessageBox QFileDialog QFontDialog QColorDialog QInp
  • smardaten实战丨谁说无代码不能开发出漂亮的门户首页?

    一 需求背景 门户首页对于一个公司或组织来说是一个极其重要的网站页面 它可以作为访问者了解和获取相关信息的入口 同时也是展示品牌形象和吸引目标受众的重要工具 开发一个门户首页需要开发团队在向访问者展示关于公司或组织基本信息的基础上 使用多种
  • 【B类比赛】 第十一届蓝桥杯 省国赛经历

    Now 拿起键盘写下这段话的时候 已经是第12届蓝桥杯省赛前的一天了 2021 4 17 距离上次蓝桥杯省赛正好6个月了 如今的我仍在ACM里 这半年经历了挺多事情 退ACM已经势在必行 且行且珍惜吧 未来的我将会接触一些新的领域 在算法之
  • 进程间通信之共享内存分析

    零拷贝技术 https strikefreedom top linux io and zero copy 一 内存映射和共享内存的区别 1 1 内存映射之mmap函数 将一个文件或者其它对象映射到进程的地址空间 实现文件磁盘地址和进程虚拟地