linux 共享内存实现

说起共享内存,一般来说会让人想起下面一些方法:
1、多线程。线程之间的内存都是共享的。更确切的说,属于同一进程的线程使用的是同一个地址空间,而不是在不同地址空间之间进行内存共享;
2、父子进程间的内存共享。父进程以MAP_SHARED|MAP_ANONYMOUS选项mmap一块匿名内存,fork之后,其子孙进程之间就能共享这块内存。这种共享内存由于受到进程父子关系的限制,一般较少使用;
3、mmap文件。多个进程mmap到同一个文件,实际上就是大家在共享文件page cache中的内存。不过文件牵涉到磁盘的读写,用来做共享内存显然十分笨重,所以就有了不跟磁盘扯上关系的内存文件,也就是我们这里要讨论的tmpfs和shmem;

tmpfs是一套虚拟的文件系统,在其中创建的文件都是基于内存的,机器重启即消失。
shmem是一套ipc,通过相应的ipc系统调用shmget能够以指定key创建一块的共享内存。需要使用这块内存的进程可以通过shmat系统调用来获得它。
虽然是两套不同的接口,但是在内核里面的实现却是同一套。shmem内部挂载了一个tmpfs分区(用户不可见),shmget就是在该分区下获取名为"SYSV${key}"的文件。然后shmat就相当于mmap这个文件。
所以我们接下来就把tmpfs和shmem当作同一个东西来讨论了。

tmpfs/shmem是一个介于文件和匿名内存之间的东西。
一方面,它具有文件的属性,能够像操作文件一样去操作它。它有自己inode、有自己的page cache;
另一方面,它也有匿名内存的属性。由于没有像磁盘这样的外部存储介质,内核在内存紧缺时不能简单的将page从它们的page cache中丢弃,而需要swap-out;(参阅《linux页面回收浅析》)

对tmpfs/shmem内存的读写,就是对page cache中相应位置的page所代表的内存进行读写,这一点跟普通的文件映射没有什么不同。
如果进程地址空间的相应位置尚未映射,则会建立到page cache中相应page的映射;
如果page cache中的相应位置还没有分配page,则会分配一个。当然,由于不存在磁盘上的源数据,新分配的page总是空的(特别的,通过read系统调用去读一个尚未分配page的位置时,并不会分配新的page,而是共享ZERO_PAGE);
如果page cache中相应位置的page被回收了,则会先将其恢复;

对于第三个“如果”,tmpfs/shmem和普通文件的page回收及其恢复方式是不同的:
page回收时,跟普通文件的情况一样,内核会通过prio_tree反向映射找到映射这个page的每一个page table,然后将其中对应的pte清空。
不同之处是普通文件的page在确保与磁盘同步(如果page为脏的话需要刷回磁盘)之后就可以丢弃了,而对于tmpfs/shmem的page则需要进行swap-out。
注意,匿名page在被swap-out时,并不是将映射它的pte清空,而是得在pte上填写相应的swap_entry,以便知道page被换出到哪里去,否则再需要这个page的时候就没法swap-in了。
而tmpfs/shmem的page呢?page table中对应的pte被清空,swap_entry会被存放在page cache的radix_tree的对应slot上。

等下一次访问触发page fault时,page需要恢复。
普通文件的page恢复跟page未分配时的情形一样,需要新分配page、然后根据映射的位置重新从磁盘读出相应的数据;
而tmpfs/shmem则是通过映射的位置找到radix_tree上对应的slot,从中得到swap_entry,从而进行swap-in,并将新的page放回page cache;

这里就有个问题了,在page cache的radix_tree的某个slot上,怎么知道里面存放着的是正常的page?还是swap-out后留下的swap_entry?
如果是swap_entry,那么slot上的值将被加上RADIX_TREE_EXCEPTIONAL_ENTRY标记(值为2)。swap_entry的值被左移两位后OR上RADIX_TREE_EXCEPTIONAL_ENTRY,填入slot。
也就是说,如果${slot} & RADIX_TREE_EXCEPTIONAL_ENTRY != 0,则它代表swap_entry,且swap_entry的值是${slot} >> 2;否则它代表page,${slot}就是指向page的指针,当然其值可能是NULL,说明page尚未分配。
那么显然,page的地址值其末两位肯定是0,否则就可能跟RADIX_TREE_EXCEPTIONAL_ENTRY标记冲突了;而swap_entry的值最大只能是30bit或62bit(对应32位或64位机器),否则左移两位就溢出了。

最后以一张图说明一下匿名page、文件映射page、tmpfs/shmem page的回收及恢复过程:

linux 共享内存实现,布布扣,bubuko.com

时间: 2024-10-15 05:04:45

linux 共享内存实现的相关文章

一张图深度解析Linux共享内存的内核实现

一张图深度解析Linux共享内存的内核实现 Sailor_forever  sailing_9806#163.com http://blog.csdn.net/sailor_8318/article/details/39484747 (本原创文章发表于Sailor_forever 的个人blog,未经本人许可,不得用于商业用途.任何个人.媒体.其他网站不得私自抄袭:网络媒体转载请注明出处,增加原文链接,否则属于侵权行为.如有任何问题,请留言或者发邮件给sailing_9806#163.com)

【转】Linux共享内存编程实例

原文地址:http://blog.csdn.net/pcliuguangtao/article/details/6526119 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 6

Linux共享内存使用常见陷阱与分析 - 51CTO.COM http://os.51cto.com/art/201311/418977_all.htmIPC---共享内存

共享内存就是允许两个或多个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据时,不需要在客户进程和服务器进程之间幅值,因此是最快的一种IPC.不同进程之间共享的内存通常安排为同一段物理内存.进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样.而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程. 注意:共享内存并未提供同步机制,也就是说,

linux 共享内存shm_open实现进程间大数据交互

linux 共享内存shm_open实现进程间大数据交互 read.c #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <sys/mman.h> #include <string.h> #include <errno.h> #include <unistd.h> /* int

unix/linux共享内存应用与陷阱

unix/linux共享内存应用与陷阱 (2012-06-12 14:32) 标签:  linux  内存  分类: linux应用  共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区.在/proc/sys/kernel/目录下,记录着共享内存的一些限制,如一个共享内存区的最大字节数shmmax,系统范围内最大共享内存区标识符数shmmni等,可以手工对其调整,但不推荐这样做.一.应用共享内存的使用,主要有以下几个API:ftok().shmget().shmat().shmdt(

Linux共享内存(一)

inux系统编程我一直看 <GNU/LINUX编程指南>,只是讲的太简单了,通常是书和网络上的资料结合着来掌握才比较全面 .在掌握了书上的内容后,再来都其他资料 . 原文链接 http://www.cnblogs.com/skyme/archive/2011/01/04/1925404.html 共享内存是系统出于多个进程之间通讯的考虑,而预留的的一块内存区.在/proc/sys/kernel/目录下,记录着共享内存的一些限制,如一个共享内存区的最大字节数shmmax,系统范围内最大共享内存区

Linux 共享内存使用

什么是共享内存 顾名思义,共享内存就是允许两个不相关的进程访问同一个逻辑内存.共享内存是在两个正在运行的进程之间共享和传递数据的一种非常有效的方式.不同进程之间共享的内存通常安排为同一段物理内存.进程可以将同一段共享内存连接到它们自己的地址空间中,所有进程都可以访问共享内存中的地址,就好像它们是由用C语言函数malloc分配的内存一样.而如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程. 特别提醒:共享内存并未提供同步机制,也就是说,在第一个进程结束对共

Linux共享内存使用常见陷阱与分析

所谓共享内存就是使得多个进程可以访问同一块内存空间,是最快的可用IPC形式.是针对其他通信机制运行效率较低而设计的.往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥.其他进程能把同一段共享内存段“连接到”他们自己的地址空间里去.所有进程都能访问共享内存中的地址.如果一个进程向这段共享内存写了数据,所做的改动会即时被有访问同一段共享内存的其他进程看到.共享内存的使用大大降低了在大规模数据处理过程中内存的消耗,但是共享内存的使用中有很多的陷阱,一不注意就很容易导致程序崩溃. 超过共享内

Linux共享内存实践(1)

共享内存基本概念 共享内存区是最快的IPC形式.一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据(如图). 共享内存 VS. 其他IPC形式 用管道/消息队列传递数据 用共享内存传递数据 (内核为每个IPC对象维护一个数据结构) 共享内存生成之后,传递数据并不需要再走Linux内核,共享内存允许两个或多个进程共享一个给定的存储区域,数据并不需要在多个进程之间进行复制,因此,共享内存的传输速度更快!! Sys