一、共享内存相关知识

所谓共享内存,就是多个进程间共同地使用同一段物理内存空间,它是通过将同一段物理内存映射到不同进程的 虚拟空间来实现的。由于映射到不同进程的虚拟空间中,不同进程可以直接使用,不需要像消息队列那样进行复制,所以共享内存的效率很高。共享内存可以通过mmap()映射普通文件机制来实现,也可以System V共享内存机制来实现,System V是通过映射特殊文件系统shm中的文件实现进程间的共享内存通信,也就是说每个共享内存区域对应特殊文件系统shm中的一个文件。

二、共享内存原理

System V共享内存把所有共享数据放在共享内存区,任何想要访问该数据的进程都必须在本进程的地址空间新增一块内存区域,用来映射存放共享数据的物理内存页面。System V共享内存通过shmget函数获得或创建一个IPC共享内存区域,并返回相应的标识符,内核在保证shmget获得或创建一个共享内存区,初始化该共享内存区相应的shmid_kernel结构,同时还将在特殊文件系统shm中创建并打开一个同名文件,并在内存中建立起该文件的相应的dentry及inode结构,新打开的文件不属于任何一个进程,所有这一切都是系统调用shmget函数完成的。

三、sysctl.conf 配置文件

以上两段说明部分是从互联网中找到的理解的内容。而做为Linux系统维护人员,能接触到的与共享内存相关的设置主要在/etc/sysctl.conf中的几个配置项。具体如下:

1kernel.shmmax = 4398046511104
2kernel.shmall = 1073741824
3kernel.shmmni = 4096

以下是redhat6官方提供的一份安装oracle的文档关于共享内存的部分介绍,如下:

LINUX shared memory
LINUX shared memory

完整版的redhat官方文档可以查看这里

注:需要注意的是free -m命令的输出里也有一项shared,不过通过查看多台主机发现,这项都是0,后来查找资料确认在free命令里共享内存这项已经废弃,没有什么用了。所以共享内存的查看不可以通过该项确认。

四、ipcs与ipcrm

ipcs

ipcs是Linux下显示进程间通信设施状态的工具。可以显示消息队列、共享内存和信号量的信息。对于程序员非常有用,普通的系统管理员一般用不到此指令。

1$ipcs -m 查看系统使用的IPC共享内存资源
2$ipcs -q 查看系统使用的IPC队列资源
3$ipcs -s 查看系统使用的IPC信号量资源
4$ipcs -l 查看系统参数配置
5默认不加参数时,使用的参数是  -a (all,显示所有)

输出示例如下:

 1# ipcs
 2------ Message Queues --------
 3key        msqid      owner      perms      used-bytes   messages
 4------ Shared Memory Segments --------
 5key        shmid      owner      perms      bytes      nattch     status
 60x6c04c831 294912     zabbix     600        219056     6
 70x0112be9b 458753     root       600        1000       7
 80x0112be9d 491522     root       600        1200712    7
 9------ Semaphore Arrays --------
10key        semid      owner      perms      nsems
110x7a04c831 1245184    zabbix     600        13
120x00000000 1802241    apache     600        1
130x00000000 1835010    apache     600        1

ipcrm

使用ipcrm 命令来清除IPC资源:这个命令同时会将与ipc对象相关联的数据也一起移除。当然,只有root用户,或者ipc对象的创建者才有这项权利;

1ipcrm -M shmkey  移除用shmkey创建的共享内存段
2ipcrm -m shmid    移除用shmid标识的共享内存段
3ipcrm -Q msgkey  移除用msqkey创建的消息队列
4ipcrm -q msqid  移除用msqid标识的消息队列
5ipcrm -S semkey  移除用semkey创建的信号
6ipcrm -s semid  移除用semid标识的信号

ipcs与ipcrm配合清理使用的资源的示例如下:

1ipcs -q | awk '{ print "ipcrm -q "$2}' | sh > /dev/null 2>&1;
2ipcs -m | awk '{ print "ipcrm -m "$2}' | sh > /dev/null 2>&1;
3ipcs -s | awk '{ print "ipcrm -s "$2}' | sh > /dev/null 2>&1;

ipcs的其他应用

使用ipcs还可以用以确认某个用户是否存在消息队列的堆积:

1、查询消息队列

1$ipcs -q
2------ Message Queues --------
3key        msqid      owner      perms      used-bytes   messages
40x49060005 58261504   user1    660        0            0
50x4f060005 58294273   user1    660        0            0

2、找出messages大于0的队列

1$ ipcs -q |grep user1 |awk '{if($5>0) print $0}'
20x00000000 1071579324 user1       644        1954530      4826
30x00000000 1071644862 user1       644        1961820      4844
40x00000000 1071677631 user1       644        1944810      4802
50x00000000 1071710400 user1       644        1961820      4844

五、为什么需要手动释放共享内存

Linux中通过API函数shmget创建的共享内存一般都是在程序中使用shmctl来释放的,但是有时为了调试程序,开发人员可能通过Ctrl + C等方式发送中断信号来结束程序,此时程序申请的共享内存就不能得到释放,当然如果程序没有改动的话,重新运行程序时仍然会使用上次申请的共享内存,但是如果我们修改了程序,由于共享内存的大小不一致等原因会导致程序申请共享内存错误。因此,我们总是希望每次结束时就能释放掉申请的共享内存。

有两种方法可以用来释放共享内存:

第一种:如果总是通过Crtl+C来结束的话,可以做一个信号处理器,当接收到这个信号的时候,先释放共享内存,然后退出程序。

第二种:不管你以什么方式结束程序,如果共享内存还是得不到释放,那么可以通过linux命令ipcrm shm shmid来释放,在使用该命令之前可以通过ipcs -m命令来查看共享内存。