0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

世上最好的共享内存(Linux共享内存最透彻的一篇)上集

Linux阅码场 来源:Linuxer 2019-11-29 14:29 次阅读

共享单车、共享充电宝、共享雨伞,世间的共享有千万种,而我独爱共享内存。

早期的共享内存,着重于强调把同一片内存,map到多个进程的虚拟地址空间(在相应进程找到一个VMA区域),以便于CPU可以在各个进程访问到这片内存。

现阶段广泛应用于多媒体、Graphics领域的共享内存方式,某种意义上不再强调映射到进程虚拟地址空间的概念(那无非是为了让CPU访问),而更强调以某种“句柄”的形式,让大家知道某一片视频、图形图像数据的存在并可以借助此“句柄”来跨进程引用这片内存,让视频encoder、decoder、GPU等可以跨进程访问内存。所以不同进程用的加速硬件其实是不同的,他们更在乎的是可以通过一个handle拿到这片内存,而不再特别在乎CPU访问它的虚拟地址(当然仍然可以映射到进程的虚拟地址空间供CPU访问)。

只要内存的拷贝(memcpy)仍然是一个占据内存带宽、CPU利用率的消耗大户存在,共享内存作为Linux进程间通信、计算机系统里各个不同硬件组件通信的最高效方法,都将持续繁荣。关于内存拷贝会大多程度地占据CPU利用率,这个可以最简单地尝试拷贝1080P,帧率每秒60的电影画面,我保证你的系统的CPU,蛋会疼地不行。

我早就想系统地写一篇综述Linux里面各种共享内存方式的文章了,但是一直被带娃这个事业牵绊,今日我决定顶着娃娃们的山呼海啸,也要写一篇文章不吐不快。

共享内存的方式有很多种,目前主流的方式仍然有:

共享内存的方式

1.基于传统SYS V的共享内存;

2.基于POSIXmmap文件映射实现共享内存;

3.通过memfd_create()和fd跨进程共享实现共享内存;

4.多媒体、图形领域广泛使用的基于dma-buf的共享内存。

共享内存

SYS V共享内存

历史悠久、年代久远、API怪异,对应内核代码linux/ipc/shm.c,当你编译内核的时候不选择CONFIG_SYSVIPC,则不再具备此能力。

你在Linux敲ipcs命令看到的share memory就是这种共享内存:

下面写一个最简单的程序来看共享内存的写端sw.c:

以及共享内存的读端sr.c:

编译和准备运行:

在此之前我们看一下系统的free:

下面运行sw和sr:

我们发现sr打印出来的和sw写进去的是一致的。这个时候我们再看下free:

可以看到used显著增大了(711632 -> 715908), shared显著地增大了(2264-> 6360),而cached这一列也显著地增大326604->330716。

我们都知道cached这一列统计的是file-backed的文件的page cache的大小。理论上,共享内存属于匿名页,但是由于这里面有个非常特殊的tmpfs(/dev/shm指向/run/shm,/run/shm则mount为tmpfs):

所以可以看出tmpfs的东西其实真的是有点含混:我们可以理解它为file-backed的匿名页(anonymous page),有点类似女声中的周深。前面我们反复强调,匿名页是没有文件背景的,这样当进行内存交换的时候,是与swap分区交换。磁盘文件系统里面的东西在内存的副本是file-backed的页面,所以不存在与swap分区交换的问题。但是tmpfs里面的东西,真的是在统计意义上统计到page cache了,但是它并没有真实的磁盘背景,这又和你访问磁盘文件系统里面的文件产生的page cache有本质的区别。所以,它是真地有那么一点misc的感觉,凡事都没有绝对,唯有变化本身是不变的。

也可以通过ipcs找到新创建的SYS V共享内存:

POSIX共享内存

我对POSIX shm_open()、mmap () API系列的共享内存的喜爱,远远超过SYS V 100倍。原谅我就是一个懒惰的人,我就是讨厌ftok、shmget、shmat、shmdt这样的API。

上面的程序如果用POSIX的写法,可以简化成写端psw.c:

读端:

编译和执行:

这样我们会在/dev/shm/、/run/shm下面看到一个文件:

坦白讲,mmap、munmap这样的API让我找到了回家的感觉,刚入行做Linux的时候,写好framebuffer驱动后,就是把/dev/fb0 mmap到用户空间来操作,所以mmap这样的 API,真的是特别亲切,像亲人一样。

当然,如果你不喜欢shm_open()这个API,你也可以用常规的open来打开文件,然后进行mmap。关键的是mmap,wikipedia如是说:

mmap

In computing, mmap(2) is a POSIX-compliant Unix system call that maps files or devices into memory. It is a method of memory-mapped file I/O. It implements demand paging, because file contents are not read from disk directly and initially do not use physical RAM at all. The actual reads from disk are performed in a "lazy" manner, after a specific location is accessed. After the memory is no longer needed, it is important to munmap(2) the pointers to it. Protection information can be managed using mprotect(2), and special treatment can be enforced using madvise(2).

POSIX的共享内存,仍然符合我们前面说的tmpfs的特点,在运行了sw,sr后,再运行psw和psr,我们发现free命令再次戏剧性变化:

请将这个free命令的结果与前2次的free结果的各个字段进行对照:

第3次比第2次的cached大了这么多?是因为我编写这篇文章边在访问磁盘里面的文件,当然POSIX的这个共享内存本身也导致cached增大了。

memfd_create

如果说POSIX的mmap让我找到回家的感觉,那么memfd_create()则是万般惊艳。见过这种API,才知道什么叫天生尤物——而且是尤物中的尤物,它完全属于那种让码农第一眼看到就会两眼充血,恨不得眼珠子夺眶而出贴到它身上去的那种API;一般人见到它第一次,都会忽略了它的长相,因为它的身材实在太火辣太抢眼了。

先不要浮想联翩,在所有的所有开始之前,我们要先提一下跨进程分享fd(文件描述符,对应我们很多时候说的“句柄”)这个重要的概念。

众所周知,Linux的fd属于一个进程级别的东西。进入每个进程的/proc/pid/fd可以看到它的fd的列表:

这个进程的0,1,2和那个进程的0,1,2不是一回事。

某年某月的某一天,人们发现,一个进程其实想访问另外一个进程的fd。当然,这只是目的不是手段。比如进程A有2个fd指向2片内存,如果进程B可以拿到这2个fd,其实就可以透过这2个fd访问到这2片内存。这个fd某种意义上充当了一个中间媒介的作用。有人说,那还不简单吗,如果进程A:

fd = open();

open()如果返回100,把这个100告诉进程B不就可以了吗,进程B访问这个100就可以了。这说明你还是没搞明白fd是一个进程内部的东西,是不能跨进程的概念。你的100和我的100,不是一个东西。这些基本的东西你搞不明白,你搞别的都是白搭。

Linux提供一个特殊的方法,可以把一个进程的fd甩锅、踢皮球给另外一个进程(其实“甩锅”这个词用在这里不合适,因为“甩锅”是一种推卸,而fd的传递是一种分享)。我特码一直想把我的bug甩(分)锅(享)出去,却发现总是被人把bug甩锅过来。

那么如何甩(分)锅(享)fd呢?

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • cpu
    cpu
    +关注

    关注

    68

    文章

    10824

    浏览量

    211109
  • Linux
    +关注

    关注

    87

    文章

    11222

    浏览量

    208888

原文标题:宋宝华:世上最好的共享内存(Linux共享内存最透彻的一篇)上集

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    Linux内存泄露案例分析和内存管理分享

    作者:京东科技 李遵举 、问题 近期我们运维同事接到线上LB(负载均衡)服务内存报警,运维同事反馈说LB集群有部分机器的内存使用率超过80%,有的甚至超过90%,而且内存使用率还再不
    的头像 发表于 10-24 16:14 688次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>内存</b>泄露案例分析和<b class='flag-5'>内存</b>管理分享

    Windows管理内存的三种主要方式

    Windows操作系统提供了多种方式来管理内存,以确保系统资源的有效利用和性能的优化。以下是关于Windows管理内存的三种主要方式的详细阐述,包括堆内存管理、虚拟内存管理以及
    的头像 发表于 10-12 17:09 398次阅读

    如何使用反射内存交换机

    反射内存交换机是种用于实现高速数据共享和通信的关键设备,以下是关于如何使用反射内存交换机的详细介绍:、前期准备 在开始使用反射
    发表于 09-14 09:23 0次下载

    16 口多模反射内存交换机:高速数据共享的核心枢纽

    在当今数字化和信息化高速发展的时代,数据的快速传输、实时共享以及高效处理成为了众多行业和领域追求的关键目标。在这样的背景下,16口多模反射内存交换机应运而生,成为了构建高性能数据共享网络的重要
    的头像 发表于 09-04 14:38 221次阅读
    16 口多模反射<b class='flag-5'>内存</b>交换机:高速数据<b class='flag-5'>共享</b>的核心枢纽

    多模反射内存交换机:实现高速实时数据共享的关键设备

    在当今数字化、信息化的时代,数据的快速传输和实时共享对于许多领域的系统运行至关重要。多模反射内存交换机作为种先进的网络设备,为满足这些需求提供了高效、可靠的解决方案。多模反射内存交换
    的头像 发表于 09-04 10:55 258次阅读
    多模反射<b class='flag-5'>内存</b>交换机:实现高速实时数据<b class='flag-5'>共享</b>的关键设备

    反射内存卡与普通内存卡的区别

    应用场景和目的反射内存卡:主要用于需要多个设备或系统之间进行高速、实时数据共享和通信的场景,例如工业控制、航空航天等领域。普通内存卡:通常用于个人电子设备,如手机、相机、平板电脑等,用于存储文件
    的头像 发表于 09-04 10:24 498次阅读
    反射<b class='flag-5'>内存</b>卡与普通<b class='flag-5'>内存</b>卡的区别

    反射内存卡原理说明

    、引言反射内存卡是种用于实现高速数据共享和实时通信的先进技术。它在多个领域,特别是对数据传输速度和实时性要求极高的应用中,发挥着关键作用。二、基本原理
    的头像 发表于 09-04 10:19 247次阅读
    反射<b class='flag-5'>内存</b>卡原理说明

    16 口多模反射内存交换机:高速数据共享的核心枢纽

    内存交换机应运而生,成为了构建高性能数据共享网络的重要组成部分。  16 口多模反射内存交换机,从字面上理解,它是种具备 16 个端口,且采用多模传输方式的反射
    的头像 发表于 07-15 10:01 261次阅读
    16 口多模反射<b class='flag-5'>内存</b>交换机:高速数据<b class='flag-5'>共享</b>的核心枢纽

    Linux内核内存管理之内核非连续物理内存分配

    我们已经知道,最好将虚拟地址映射到连续页帧,从而更好地利用缓存并实现更低的平均内存访问时间。然而,如果对内存区域的请求并不频繁,那么考虑基于通过连续线性地址访问非连续页帧的分配方案是有意义的。该模式
    的头像 发表于 02-23 09:44 864次阅读
    <b class='flag-5'>Linux</b>内核<b class='flag-5'>内存</b>管理之内核非连续物理<b class='flag-5'>内存</b>分配

    内存共享原理解析

    内存共享种在多个进程之间共享数据的机制,它允许不同的进程直接访问同内存区域,从而实现数据
    的头像 发表于 02-19 15:11 1197次阅读
    <b class='flag-5'>内存</b><b class='flag-5'>共享</b>原理解析

    Linux内核内存管理架构解析

    内存管理子系统可能是linux内核中最为复杂的个子系统,其支持的功能需求众多,如页面映射、页面分配、页面回收、页面交换、冷热页面、紧急页面、页面碎片管理、页面缓存、页面统计等,而且对性能也有很高
    的头像 发表于 01-04 09:24 632次阅读
    <b class='flag-5'>Linux</b>内核<b class='flag-5'>内存</b>管理架构解析

    java虚拟机内存包括远空间内存

    详细介绍JVM内存的各个部分及其作用。 Java堆(Heap) Java堆是JVM管理的最大内存区域,用于存放Java对象实例。在堆中分配内存由垃圾收集器(GC)自动进行,主要负责
    的头像 发表于 12-05 14:15 375次阅读

    jvm内存区域中,哪块是属于线程共享

    JVM(Java虚拟机)是种计算机软件,用于执行Java字节码。在JVM中,存在多个内存区域,包括线程共享内存区域。本文将详细介绍JVM内存
    的头像 发表于 12-05 14:14 1313次阅读

    jvm内存模型和内存结构

    JVM(Java虚拟机)是Java程序的运行平台,它负责将Java程序转换成机器码并在计算机上执行。在JVM中,内存模型和内存结构是两个重要的概念,本文将详细介绍它们。 、JVM内存
    的头像 发表于 12-05 11:08 889次阅读

    VMIPCI5565反射内存卡通信协议

    反射内存网: 基于实时特性的共享内存网络,数据传输速率高,响应时间确定,适用于高速数据同步,过程控制及实时测试测量等领域。 VMIC反射内存网络是基于环型/星型拓扑的,高速复制的
    的头像 发表于 11-29 14:48 468次阅读