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

    文章

    10442

    浏览量

    206549
  • Linux
    +关注

    关注

    87

    文章

    10990

    浏览量

    206734

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

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

收藏 人收藏

    评论

    相关推荐

    内存共享原理解析

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

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

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

    EC SRAM映射到CPU Memory空间的共享内存设计

    ShareMemory,顾名思义就是共享内存。这个概念在很多计算机系统中都存在,本文特指 EC SRAM 映射到 CPU Memory 空间的共享内存设计。
    的头像 发表于 11-18 15:11 685次阅读
    EC SRAM映射到CPU Memory空间的<b class='flag-5'>共享</b><b class='flag-5'>内存</b>设计

    Linux 内存管理总结

    一、Linux内存管理概述 Linux内存管理是指对系统内存的分配、释放、映射、管理、交换、压缩等一系列操作的管理。在
    的头像 发表于 11-10 14:58 241次阅读
    <b class='flag-5'>Linux</b> <b class='flag-5'>内存</b>管理总结

    什么是内存碎片Linux

    什么是内存碎片? 内存碎片在Linux很早的时候就已经出现了,了解早期内存碎片产生的历史,有利于我们对它的理解。 假设现在有一块32MB大小的内存
    的头像 发表于 10-08 10:12 369次阅读
    什么是<b class='flag-5'>内存</b>碎片<b class='flag-5'>Linux</b>

    使用Rust语言的WinAPI模块来实现共享内存

    进程间通信(IPC)是操作系统中非常重要的一部分,它使得不同的进程可以在不同的计算机上进行通信。在Windows操作系统中,共享内存是一种常见的IPC机制,它可以在不同的进程之间共享数据,以便它们
    的头像 发表于 09-19 16:15 1009次阅读

    Linux内核的内存管理详解

    内存管理的主要工作就是对物理内存进行组织,然后对物理内存的分配和回收。但是Linux引入了虚拟地址的概念。
    发表于 08-31 14:46 425次阅读
    <b class='flag-5'>Linux</b>内核的<b class='flag-5'>内存</b>管理详解

    如何查看linux程序共享库呢?

    linux系统中,程序通常需要依赖于外部库来正常工作。这些库可以直接编译到程序中,也可以从共享库池中加载。
    的头像 发表于 08-28 09:11 979次阅读
    如何查看<b class='flag-5'>linux</b>程序<b class='flag-5'>共享</b>库呢?

    Linux内存相关知识科普

    Linux 内存是后台开发人员,需要深入了解的计算机资源。合理的使用内存,有助于提升机器的性能和稳定性。本文主要介绍**Linu****x 内存组织结构和页面布局,
    发表于 07-25 14:43 551次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>内存</b>相关知识科普

    Linux下进程间共享内存通信常用的同步机制

    今天我们来讲讲进程间使用共享内存通信时为了确保数据的正确,如何进行同步?
    发表于 06-20 09:41 599次阅读

    Linux进程间如何实现共享内存通信

    在上面的例程中,我们首先使用ftok()函数生成一个key值作为共享内存的标识符。然后使用shmget()函数创建共享内存区域,shmaddr指向
    发表于 06-19 09:55 428次阅读

    CUDA编程分布式共享内存

    计算能力9.0中引入的线程块集群为线程块集群中的线程提供了访问集群中所有参与线程块的共享内存的能力。
    的头像 发表于 05-19 15:35 923次阅读

    CUDA编程共享内存

    共享内存是使用__shared__内存空间说明符分配的。
    的头像 发表于 05-19 15:32 798次阅读
    CUDA编程<b class='flag-5'>共享</b><b class='flag-5'>内存</b>

    Linux进程间共享内存通信时如何同步?

    今天我们来讲讲进程间使用共享内存通信时为了确保数据的正确,如何进行同步?
    的头像 发表于 05-11 18:25 1227次阅读

    反射内存网络简介

    反射内存网络(RFM网络)是基于环状/星状、高速复制的共享内存网络。它支持不同总线结构的多计算机系统,并且可以使用不同的操作系统来共享高速的,稳定速率的实时数据。
    的头像 发表于 04-30 21:15 574次阅读