共享内存是系统级别的接口
进程间通信的本质是,让不同的进程看到同一份资源
共享内存的处理不同于管道

system V下的共享内存生命周期是跟随内存的,如果不显示删除就需要os重启解决
ipcs -m查看当前用户创建的共享内存
ipcem -m shmid删除对应的共享内存
key是共享内存的内核标识符,shmid是用户层面的标识符

共享内存也是有权限的,0就是都不能访问

1.共享内存的原理

共享库会映射到堆栈中间的区域:
把磁盘中的数据加载到内存中,操作系统建立映射,经过页表映射到地址空间中的共享区中,需要库就跳转过去执行。不止是库可以映射

  • 两个进程有各自的页表,映射到物理内存的不同区域,所以有了独立性
  • 现有一个特定的接口,能在物理内存中创建好空间
  • 把这个共享空间,通过这个两个进程调用该接口映射到各自的地址空间中
  • 把这个空间的起始地址返回给用户,用户就能找到这个空间了

共享内存转 redis 共享内存实现_操作系统

2.使用共享内存步骤:

  1. 创建共享内存;
  2. 附加,将进程附加该共享内存上(将进程虚拟地址和物理地址通过页表建设映射关系);
  3. 分离,将虚拟地址和物理地址的映射关系从页表中删除

共享内存映射到物理地址空间时 ,是映射在共享区中(在栈区和堆区中间)
在使用共享内存时,进程就把他当作自己的空间使用就行

3.共享内存接口:

创建共享内存就是os在物理内存中开辟一段空间
os看待物理内存是将其(一页4kb,4G内存有2^20个页)看成这么多页
os需要管理这些页,通过数组管理,这个数组类型就是共享内存的各个属性

进程通信时,共享内存需要其中一个进程创建,flag就是处理进程面对有无共享内存的情况

创建或者获取共享内存shmget

共享内存转 redis 共享内存实现_共享内存转 redis_02

  • key值由用户提供,是共享内存的唯一值
    原因:
    如果是os提供,另一个进程怎么知道共享内存呢,为了让两个进程看到同一个共享内存,所以让两个进程拥有同一个key值就行
  • 如何保证key的值唯一
    这个函数找到特定的文件,结合自己设定的值(0-255),会将文件的inode和项目id做组合形成一过唯一值返回给key

共享内存转 redis 共享内存实现_共享内存转 redis_03


creat含义是获取内存,不存在就创建


execl含义如果不存在指定的共享内存,则创建,存在就出错返回;可以保证get函数调用成功是一过全新的内存

  • 搭配使用是要获得自己创建的共享内存,不使用别人的
  • 共享内存创建时也需要设置权限信息,需要按位或上共享内存的权限(八进制数字)表示
    大小最好设置成页的整数倍(4kb)

共享内存大小最好设置成页的整数倍,os和磁盘io时基本单位是4kb,

内存在哪:内核中维护共享内存的结构

附加接口:将共享内存附加到当前内存上

共享内存转 redis 共享内存实现_共享内存转 redis_04


附加上后,就是进程多了一份内存空间

分离: 将共享内存从进程中分离出来,分离时需告诉shmdt函数刚附加共享内存到进程后,进程虚拟地址的位置

共享内存转 redis 共享内存实现_linux_05

控制共享内存: 获取属性,设置属性,删除共享内存

共享内存转 redis 共享内存实现_共享内存转 redis_06


共享内存转 redis 共享内存实现_共享内存转 redis_07

4.共享内存的命令

ipcs:输出消息队列,共享内存,信号量信息

共享内存转 redis 共享内存实现_操作系统_08

ipcs -m:只输出共享内存信息

共享内存转 redis 共享内存实现_物理内存_09

key

共享内存标识符

shimd

共享内存操作句柄

owner

内存创建者

perms

内存权限

bytes

内存大小

nattch

附加进程数量

statu

没有显式表示该共享内存正常

ipcrm -m +shmid 将共享内存从物理内存中删除

  • 内核中有一个结构体维护着在物理空间的共享内存
  • 删除0附加进程的共享内存,则内核当中的结构体和物理空间也被删除
  • 删除有附加进程的共享内存,则将该共享内存的key(标识符)变成0x 0000 0000;
    表示当前共享内存不能被其它进程附加,共享内存的状态被置就被置为dest;
    该现象是因为内核中描述共享内存的结构体没有被删除(如下图所示);

删除后产生了两种结果的原因:

  • 共享内存的物理空间没有被其它内存使用,则能正常运行;
  • 如果该空间被别的进程使用就会崩溃;
描述共享内存的结构体内部的引用计数一旦为0(mywrite进程停止),则共享内存结构体被释放

共享内存转 redis 共享内存实现_操作系统_10

共享内存的特性:

共享内存是写的时候是覆盖写,读的时候是拷贝(也就是数据访问)

  • 将字符串写入共享内存后,写操作进程结束,在多次读取依旧能多次读取成功;
  • 所以共享内存的生命周期跟随操作系统内核,不主动删除则一直存在;

基于共享内存+管道的访问控制

进程退出,共享内存依然是存在的,生命周期是随内存的
shmid是提供给用户的,ipcrm -m删除时就删shmid
申请4097个大小的共享内存,OS会申请8kb大小,但是只能使用4097个字节

因为共享内存无法做到访问控制,读端会一直读取数据

共享内存转 redis 共享内存实现_linux_11


共享内存转 redis 共享内存实现_操作系统_12


共享内存转 redis 共享内存实现_linux_13