共享内存shmat shmget shmdt shmctl ipcs ipcmk ipcrm

本文详细介绍了Linux下共享内存的使用,包括通过ipcs、ipcmk、ipcrm进行管理,以及 shmget、shmat、shmdt、shmctl 的API用法,探讨了权限设置和内存大小限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ipcs -m

ipcmk -M 1024(size)
ipcmk -M 1024(size) -p 0666
ipcrm -m 1024(id)


size的上限:4G
[ chenming@localhost src]$ cat /proc/sys/kernel/shmmax
4294967295

-----------------------------API---------------------------------
#include <sys/types.h>
#include <sys/shm.h>

shmget的用法:  出错返回-1,否则返回int,作为shmid
只新建:shmget( IPC_PRIVATE, shm_size, 0666);
有则获取,没有则报错: shm_id = shmget(shm_num, 0,  0666或SHM_R);
有则获取,没有则新建: shm_id = shmget(shm_num, shm_size,   IPC_CREAT|0666);
没有则新建,有则报错:  shm_id = shmget(shm_num, shm_size,  IPC_CREAT|IPC_EXCL |0666);

shmat
void *shmat(int shmid, const void *shmaddr, int shmflg);
shmat(shmid, NULL, 0)   读写
shmat(shmid, NULL, SHM_RDONLY)   只读
返回指针或(void*)-1

shmdt(ptr)
返回0或-1

删:
shmctl(shmid, IPC_RMID, 0)

struct shmid_ds  buf;
shmctl(shmid, IPC_STAT, &buf);
osl::MemoryDataStream os(shmptr, buf.shm_segsz, false);


0666权限的构成:
SHM_R  | SHM_W | (SHM_R>>3) | (SHM_W>>3) | (SHM_R>>6) | (SHM_W>>6)

<think>我们正在讨论的是共享内存shmget)而非信号量(semget)。用户希望确保使用shmget创建的共享内存不会被系统占用(即避免资源泄漏)。关键点在于:共享内存需要显式删除,否则会一直存在直到系统重启。根据引用[1]:共享内存的生命周期独立于进程,必须显式删除(shmctlwithIPC_RMID)或等待系统重启才能释放。解决方案:1.编程时确保在不再需要共享内存时调用shmctl(shmid,IPC_RMID,NULL)来标记删除。2.当所有进程都分离(shmdt共享内存且已标记删除时,系统才会实际回收内存。3.使用atexit()或信号处理程序来确保程序异常退出时也能删除共享内存。4.使用命令行工具(ipcs/ipcrm)来监控和清理。测试方法:1.编写程序,创建共享内存,然后正常退出(不带删除操作),使用ipcs检查是否残留。2.编写程序,创建共享内存,并在退出前调用删除,使用ipcs检查是否被删除。代码示例:创建共享内存但不删除(模拟泄漏):```c#include<sys/ipc.h>#include<sys/shm.h>#include<stdio.h>#include<stdlib.h>intmain(){key_tkey=ftok("/tmp",65);intshmid=shmget(key,1024,0666|IPC_CREAT);//这里故意不删除return0;}```运行后,使用命令:`ipcs-m`查看,会看到创建的共享内存。另一种情况:正常删除```c#include<sys/ipc.h>#include<sys/shm.h>#include<stdio.h>#include<stdlib.h>intmain(){key_tkey=ftok("/tmp",65);intshmid=shmget(key,1024,0666|IPC_CREAT);//...使用共享内存...//删除共享内存shmctl(shmid,IPC_RMID,NULL);return0;}```运行后,再用`ipcs-m`查看,应该看不到。另外,可以编写一个监控脚本,在程序运行前后检查共享内存的数量。最佳实践:-使用atexit注册清理函数。-在程序异常退出时(如收到信号)进行清理。例如:```c#include<sys/ipc.h>#include<sys/shm.h>#include<stdio.h>#include<stdlib.h>#include<signal.h>intshmid;voidcleanup(){shmctl(shmid,IPC_RMID,NULL);}voidhandle_signal(intsig){cleanup();exit(1);}intmain(){key_tkey=ftok("/tmp",65);shmid=shmget(key,1024,0666|IPC_CREAT);atexit(cleanup);signal(SIGINT,handle_signal);signal(SIGTERM,handle_signal);//...主程序逻辑...//注意:如果正常退出,atexit会调用cleanupreturn0;}```注意:多个进程使用同一共享内存时,通常由一个进程(创建者)负责删除。或者使用引用计数,但SystemV共享内存本身不提供引用计数,需要额外机制(如信号量)来协调。引用[1]中强调了共享内存的独立生命周期和显式删除的必要性。相关问题:1.如何检测共享内存泄漏?2.多个进程使用同一共享内存时,如何确定由哪个进程负责删除?3.SystemV共享内存和POSIX共享内存(shm_open)在生命周期管理上有何不同?</think> ### Linux系统中确保`shmget`创建的共享内存不被系统占用的解决方案 要避免共享内存被系统占用(即资源泄漏),需在编程和系统层面双管齐下。以下是基于引用[1]的核心原则的解决方案: #### 一、编程关键措施(核心防御) 1. **显式删除机制** 创建共享内存后必须调用`shmctl(IPC_RMID)`: ```c #include <sys/shm.h> int shmid = shmget(key, size, IPC_CREAT | 0666); /* 使用共享内存... */ shmctl(shmid, IPC_RMID, NULL); // 显式删除[^1] ``` 2. **自动资源回收** ```c void cleanup() { shmctl(shmid, IPC_RMID, NULL); } int main() { atexit(cleanup); // 注册退出钩子 signal(SIGTERM, cleanup); // 信号中断处理 // ...主程序逻辑... } ``` 3. **引用计数管理** 对长期运行的共享内存: ```c struct shmid_ds info; shmctl(shmid, IPC_STAT, &info); if(info.shm_nattch == 0) // 无进程连接时删除 shmctl(shmid, IPC_RMID, NULL); ``` #### 二、系统级监控(主动防御) 1. **泄漏检测命令** ```bash # 创建前后对比 ipcs -m > before.log ./your_program ipcs -m > after.log diff before.log after.log ``` 2. **定时清理脚本** ```bash #!/bin/bash # 清理12小时未使用的共享内存 ipcs -m | awk '$6 == 0 && $1 ~ /0x[0-9a-f]+/ {print "ipcrm -m", $2}' | sh ``` 3. **内核参数调优** 修改`/etc/sysctl.conf`防止内存碎片化: ```ini kernel.shmall = 4294967296 # 最大共享内存页数[^2] kernel.shmmax = 68719476736 # 单段最大字节数 kernel.shmmni = 4096 # 最大段数 ``` #### 三、验证测试方案 1. **基础验证代码** ```c #include <sys/shm.h> int main() { key_t key = ftok("/tmp", 'm'); int shmid = shmget(key, 1024, IPC_CREAT | 0666); shmctl(shmid, IPC_RMID, NULL); // 立即删除 // 验证是否可重复创建 int new_id = shmget(key, 1024, 0666 | IPC_EXCL); if(new_id != -1) printf("✅ 删除成功"); else perror("❌ 删除失败"); } ``` 2. **压测验证脚本** ```bash for i in {1..1000}; do ./test_program & sleep 0.01 ipcs -m | grep "0x$(printf '%x' $(stat -c%i /tmp))" done ``` #### 四、高级防护机制 1. **内核模块监控** ```c // LKM示例 hook shmat/shmat #include <linux/linkage.h> long (*orig_shmget)(key_t, size_t, int); long hacked_shmget(key_t key, size_t size, int shmflg) { if(!(shmflg & IPC_CREAT)) printk("WARN: non-creator access %llx\n", key); return orig_shmget(key, size, shmflg); } ``` 2. **CGroup内存限制** ```bash cgcreate -g memory:/shm_group echo $((1024*1024)) > /sys/fs/cgroup/memory/shm_group/memory.limit_in_bytes cgexec -g memory:shm_group ./your_program ``` > **关键原则**:共享内存生命周期独立于进程[^1],必须通过 **显式删除**(`shmctl(IPC_RMID)`)或 **系统重启** 才能释放。碎片化内存可通过`echo 3 > /proc/sys/vm/drop_caches`清理[^4]。 --- ### 相关问题 1. 如何检测跨进程共享内存的引用计数? 2. `shmdt()`和`shmctl(IPC_RMID)`有何本质区别? 3. System V共享内存与POSIX共享内存的生命周期管理差异? 4. 内核如何通过`kmem_cache_create`管理共享内存对象?[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值