3

共享内存与内存映射(mmap)「转载的哦」

 2 years ago
source link: https://weedge.github.io/%E8%BD%AC%E8%BD%BD/mmap/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

共享内存与内存映射(mmap)「转载的哦」

2021-11-16

from: https://www.cnblogs.com/huangfuyuan/p/9476951.html

首先关于共享内存的链接:共享内存里面包含了创建共享内存区域的函数,以及两个进程怎么挂载共享内存通信,分离、释放共享内存

共享内存的好处就是效率高,不需要太多次的进行数据的copy。可以直接进行读写内存。所以,相对来说在IPC进程间通信三大主题(消息队列,信号量,共享内存)里面,共享内存要比消息队列使用多,而且消息队列只在有血缘关系的进程间通信;但是,共享内存不保证同步,可以使用信号量来保证共享内存同步。Linux中的两种共享内存。一种是我们的IPC通信System V版本的共享内存,另外的一种就是我们今天提到的存储映射I/O(mmap函数),当然还有一种POSIX的共享内存,它是在mmap基础之上构建的。

mmap I/O的描述符间接说明内存映射是对文件操作。另外,mmap另外可以在无亲缘的进程之间提供共享内存区。这样,类似的两个进程之间就是可以进行了通信。

Linux提供了内存映射函数mmap, 它把文件内容映射到一段内存上(准确说是虚拟内存上,运行着进程), 通过对这段内存的读取和修改, 实现对文件的读取和修改。mmap()系统调用使得进程之间可以通过映射一个普通的文件实现共享内存。普通文件映射到进程地址空间后,进程可以像访问内存的方式对文件进行访问,不需要其他内核态的系统调用(read,write)去操作。

这里是讲设备或者硬盘存储的一块空间映射到物理内存,然后操作这块物理内存就是在操作实际的硬盘空间,不需要经过内核态传递。比如你的硬盘上有一个文件,你可以使用linux系统提供的mmap接口,将这个文件映射到进程一块虚拟地址空间,这块空间会对应一块物理内存,当你读写这块物理空间的时候,就是在读取实际的磁盘文件,就是这么直接高效。通常诸如共享库的加载都是通过内存映射的方式加载到物理内存的

mmap系统调用并不完全是为了共享内存来设计的,它本身提供了不同于一般对普通文件的访问的方式,进程可以像读写内存一样对普通文件进行操作(无需系统调用),IPC的共享内存是纯粹为了共享。

mmap系统调用介绍

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

这就是mmap系统调用的接口,mmap函数成功返回指向内存区域的指针,失败返回MAP_FAILED。

  • addr,某个特定的地址作为起始地址,当被设置为NULL,标识系统自动分配地址。实实在在的物理区域。

  • length说的是内存段的长度。

  • prot是用来设定内存段的访问权限。

    prot参数 说明
    PROT_READ 内存段可读
    PROT_WRITE 内存段可写
    PROT_EXEC 内存段可执行
    PROT_NONE 内存段不能被访问
  • fd参数是用来被映射文件对应的文件描述符。通过open系统调用得到。

    flags参数 说明
    MAP_SHARED 进程间共享内存,对该内存段修改反映到映射文件中。提供了POSIX共享内存
    MAP_PRIVATE 内存段为调用进程所私有。对该内存段的修改不会反映到映射文件
    MAP_ANNOYMOUS 这段内存不是从文件映射而来的。内容被初始化为全0
    MAP_FIXED 内存段必须位于start参数指定的地址处,start必须是页大小的整数倍(4K整数倍)
    MAP_HUGETLB 按照大内存页面来分配内存空间
  • offset设定从何处进行映射。

mmap用于共享内存的方式

  1. 我们可以使用普通文件进行提供内存映射,例如,open系统调用打开一个文件,然后进行mmap操作,得到共享内存,这种方式适用于任何进程之间。
  2. 以使用特殊文件进行匿名内存映射,这个相对的是具有血缘关系的进程之间,当父进程调用mmap,然后进行fork,这样父进程创建的子进程会继承父进程匿名映射后的地址空间,这样,父子进程之间就可以进行通信了。相当于是mmap的返回地址此时是父子进程同时来维护。
  3. 另外POSIX版本的共享内存底层也是使用了mmap。所以,共享内存在在posix上一定程度上就是指的内存映射了

mmap和System V共享内存的比较

System V版本的共享内存(以下我们统称为shm)

https://gitee.com/lienhui68/picStore/raw/master/null/20200917180539.png

mmap版本的共享内存

https://gitee.com/lienhui68/picStore/raw/master/null/20200917180729.png

  1. mmap是在磁盘上建立一个文件,每个进程地址空间中开辟出一块空间进行映射。而shm共享内存,每个进程最终会映射到同一块物理内存。shm保存在物理内存,这样读写的速度肯定要比磁盘要快,但是存储量不是特别大。
  2. 相对于shm来说,mmap更加简单,调用更加方便,所以这也是大家都喜欢用的原因。
  3. 另外mmap有一个好处是当机器重启,因为mmap把文件保存在磁盘上,这个文件还保存了操作系统同步的映像,所以mmap不会丢失,但是shmget在内存里面就会丢失。
  4. 总之,shm是在内存中创建空间,每个进程映射到此处。内存映射是创建一个文件,并且映射到每个进程开辟的空间中。

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK