Linux系统--进程间通信--共享内存相关指令
Linux系统–进程间通信–共享内存相关指令
核心概念回顾:
- 共享内存: 允许多个进程访问同一块物理内存区域,是进程间通信(IPC)中最快的方式之一,因为它避免了内核空间和用户空间之间的数据复制。
- System V IPC: Linux 继承了 Unix System V 的 IPC 机制,包括共享内存、消息队列和信号量。这些 IPC 对象由内核管理,并通过唯一的标识符(
key
或shmid
)访问。 key
(ftok
): 一个整数值,通常由ftok()
函数根据文件路径和项目 ID 生成,用于在进程间约定访问同一个 IPC 对象。shmid
: 共享内存标识符。当进程成功创建或连接到共享内存段后,内核返回此 ID。后续操作(如附加、分离、控制)通常使用此 ID。- 权限 (
shm_perm
): 定义了共享内存段的访问权限(属主、属组、其他用户的读/写权限)和属主/属组信息。
主要相关命令:
Linux 没有专门为共享内存设计的单一“创建”或“附加”命令(这些操作通常在 C/C++ 程序中使用 shmget()
, shmat()
, shmdt()
, shmctl()
系统调用完成)。管理共享内存的主要工具是查看和删除 IPC 对象的通用命令:
ipcs
(IPC Status)ipcrm
(IPC Remove)
此外,了解 /proc
文件系统下的接口也很重要:
/proc/sysvipc/shm
详细讲解每个命令:
1. ipcs
- 查看 IPC 状态
-
作用: 显示当前系统中存在的 System V IPC 对象的信息,包括共享内存(Shared Memory)、消息队列(Message Queues)和信号量(Semaphore)。它是查看共享内存状态的主要工具。
-
语法:
ipcs [options]
-
常用命令行参数 (针对共享内存):
-m
或--shm-mems
: 只显示共享内存段的信息。(最常用)-i <shmid>
或--id <shmid>
: 显示指定 ID (shmid
) 的共享内存段的详细信息。-l
或--limits
: 显示系统对 IPC 资源的限制(如最大共享内存段大小、最大段数等)。-p
或--pid
: 显示创建者和最后操作者的进程 ID (PID)。-t
或--time
: 显示附加时间 (attached-time
)、分离时间 (detached-time
) 和变更时间 (changed-time
)。时间格式可以用-u
指定为秒。-c
或--creator
: 显示创建者信息(用户和组)。-b
或--bytes
: 以字节为单位显示大小(默认单位可能因系统而异,通常是 KB)。-u
或--summary
: 显示 IPC 资源使用的摘要信息。-a
或--all
: 显示所有信息(相当于-m -q -s -c -l -u -p -t
)。输出可能很长。--human
: 以人类可读的格式显示大小(例如,K, M, G)。
-
输出字段解释 (使用
ipcs -m
时):key
: 共享内存段的键值 (ftok
生成或IPC_PRIVATE
)。shmid
: 共享内存段的唯一标识符。owner
: 共享内存段的所有者。perms
: 访问权限(八进制表示,如666
)。bytes
: 共享内存段的大小(单位受-b
参数影响)。nattch
: 当前附加(连接)到该共享内存段的进程数量。status
: 状态标志(如dest
表示该段已被标记为待销毁,当nattch
为 0 时会被内核删除)。attached-time
,detached-time
,changed-time
: 时间信息(需要-t
参数)。creator-uid
,creator-gid
,cuid
,cgid
: 创建者和所有者的 UID/GID(需要-c
参数)。lpid
,cpid
: 最后操作该段的进程 PID (lpid
) 和创建该段的进程 PID (cpid
)(需要-p
参数)。
-
使用示例:
-
查看所有共享内存段:
$ ipcs -m ------ Shared Memory Segments -------- key shmid owner perms bytes nattch status 0x00000000 32768 user 600 524288 2 dest 0x0000abcd 65537 user 666 1024 1
-
查看指定
shmid
的详细信息:$ ipcs -m -i 65537 Shared memory Segment shmid=65537 uid=1000 gid=1000 cuid=1000 cgid=1000 mode=0666 access_perms=0666 bytes=1024 lpid=1234 cpid=5678 nattch=1 att_time=Sat Oct 12 11:15:30 2025 det_time=Sat Oct 12 11:15:30 2025 change_time=Sat Oct 12 11:15:30 2025
-
查看共享内存系统限制:
$ ipcs -m -l ------ Shared Memory Limits -------- max number of segments = 4096 max seg size (kbytes) = 18014398509465599 max total shared memory (kbytes) = 18014398509481980 min seg size (bytes) = 1
-
查看共享内存段并显示创建者和最后操作者的 PID:
$ ipcs -m -p ------ Shared Memory Segments -------- key shmid owner perms bytes nattch cpid lpid 0x00000000 32768 user 600 524288 2 7890 1234 0x0000abcd 65537 user 666 1024 1 5678 5678
-
查看共享内存段摘要:
$ ipcs -m -u ------ Shared Memory Status -------- segments allocated 2 pages allocated 513 (524288 bytes) pages resident 513 pages swapped 0 Swap performance: 0 attempts, 0 successes
-
-
注意事项:
- 需要足够的权限才能查看不属于当前用户的共享内存段信息(通常是 root 或目标段的所有者)。
- 理解输出字段的含义对于诊断问题至关重要(如
nattch
,status
,lpid
)。 key
为0x00000000
通常是使用IPC_PRIVATE
创建的段。
2. ipcrm
- 删除 IPC 对象
-
作用: 删除指定的 System V IPC 对象,包括共享内存段、消息队列和信号量集。它是移除不再需要的共享内存段的主要命令行工具。
-
语法:
ipcrm [options]
-
常用命令行参数 (针对共享内存):
-m <shmid>
或--shmemid <shmid>
: 删除指定shmid
的共享内存段。-M <shmkey>
或--shmemkey <shmkey>
: 删除具有指定key
的共享内存段。<shmkey>
可以是ipcs -m
输出的key
列的数值(通常是十六进制,但这里需要十进制表示!)或十六进制(以0x
开头)。-a
或--all [shm|msg|sem]
: 删除当前用户拥有的所有 IPC 对象。可以指定类型(shm
,msg
,sem
),如果不指定则删除所有三种类型。(非常危险!)-Q <msgkey>
,-q <msgid>
,-S <semkey>
,-s <semid>
: 用于删除消息队列和信号量(与共享内存无关)。
-
使用示例:
-
通过
shmid
删除共享内存段:$ ipcs -m # 先查看,假设要删除 shmid=65537 $ ipcrm -m 65537
-
通过
key
删除共享内存段:- 假设
ipcs -m
显示key
为0x0000abcd
。 - 需要将十六进制
0x0000abcd
转换为十进制43981
,或者直接使用十六进制格式(带0x
):
$ ipcrm -M 0x0000abcd # 推荐:直接使用十六进制 key # 或者 $ ipcrm -M 43981 # 使用十进制表示(43981 是 0xabcd 的十进制)
- 假设
-
删除当前用户创建的所有共享内存段: (谨慎使用!)
$ ipcrm -a shm
-
-
注意事项:
- 极其危险:
ipcrm
会直接删除内核中的 IPC 对象。如果仍有进程附加(nattch > 0
)到该共享内存段,删除操作会立即将该段标记为销毁(status
显示dest
)。一旦所有进程都分离(nattch
变为 0),内核会立即销毁该段及其内容。 这会导致仍在使用该段的进程出现错误(如SIGSEGV
段错误)或读取到无效数据。 - 权限: 通常只有 root 用户或共享内存段的创建者(所有者)才能删除它。
key
的表示: 使用-M
参数时,<shmkey>
可以是十进制数字或十六进制(以0x
开头)。ipcs
默认输出十六进制key
,直接复制到ipcrm -M 0x...
最方便。-a
的危险性:ipcrm -a
或ipcrm -a shm
会删除当前用户创建的所有共享内存段。如果该用户运行了多个使用共享内存的服务,这个命令会同时破坏所有这些服务。在生产环境中绝对禁止随意使用! 务必先用ipcs -m
确认要删除的对象。- 孤儿对象: 如果创建共享内存段的进程异常终止(没有调用
shmctl(..., IPC_RMID, ...)
),共享内存段会变成“孤儿”,一直存在直到被手动删除或系统重启。ipcrm
是清理这些孤儿对象的主要方法。 - 系统重启: 系统重启会清除所有 IPC 对象(包括共享内存)。
- 极其危险:
3. /proc/sysvipc/shm
- 通过 proc 文件系统查看共享内存
-
作用: 这不是一个命令,而是 Linux
/proc
虚拟文件系统提供的一个文件。读取该文件的内容可以获取当前系统中所有 System V 共享内存段的详细信息,格式比ipcs
更原始但也更全面。 -
使用方法: 使用文本查看命令(如
cat
,less
,more
)读取该文件。$ cat /proc/sysvipc/shm
-
输出字段解释: 输出是一个表格,每行代表一个共享内存段,字段以空格分隔。字段顺序通常是:
shmid
: 共享内存段 ID。key
: 键值(十进制)。shmid
: (再次出现,有时是shmseg
,含义相同)。perms
: 权限(八进制)。size
: 大小(字节)。cpid
: 创建者 PID。lpid
: 最后操作(shmat
/shmdt
)的进程 PID。nattch
: 当前附加的进程数。uid
: 所有者 UID。gid
: 所有者 GID。cuid
: 创建者 UID。cgid
: 创建者 GID。atime
: 最后附加时间(自 1970-01-01 00:00:00 UTC 起的秒数)。dtime
: 最后分离时间(自 1970-01-01 00:00:00 UTC 起的秒数,0 表示未分离)。ctime
: 最后变更时间(权限、所有者等变更,自 1970-01-01 00:00:00 UTC 起的秒数)。rss
: 驻留集大小(实际在物理内存中的部分,字节)。swap
: 被交换到磁盘的大小(字节)。
-
使用示例:
$ cat /proc/sysvipc/shm 65537 43981 65537 666 1024 5678 1234 1 1000 1000 1000 1000 1697091330 0 1697091330 1024 0 32768 0 32768 600 524288 7890 1234 2 1000 1000 1000 1000 1697091200 0 1697091200 524288 0
(需要根据上面的字段顺序自行解析)
-
注意事项:
- 输出是原始数据,没有表头,需要对照字段顺序理解。
- 时间戳是 epoch 时间(秒数),需要转换才能理解。
- 提供的信息比
ipcs
更底层和详细(如rss
,swap
)。 - 主要用于脚本解析或需要非常详细信息的情况。日常管理使用
ipcs
更直观方便。 - 需要读取权限(通常
/proc
下的文件对所有用户可读)。
总结与重要注意事项:
- 核心命令:
ipcs
(查看) 和ipcrm
(删除) 是管理共享内存的主要命令行工具。/proc/sysvipc/shm
提供底层信息。 - 创建与附加: 共享内存段的创建 (
shmget
) 和附加 (shmat
) 通常在应用程序内部(C/C++等)使用系统调用完成,没有直接对应的命令行工具。命令行主要用于管理和监控。 - 删除的危险性:
ipcrm
是极其危险的操作。 务必先用ipcs -m
确认目标共享内存段,确保没有关键进程(nattch
应为 0 或确认可以安全中断)在使用它。误删会导致进程崩溃或数据丢失。生产环境操作务必谨慎! - 权限: 查看和删除共享内存段通常需要 root 权限或你是该段的所有者。
- 孤儿对象: 程序崩溃可能导致共享内存段残留。定期使用
ipcs -m
检查并使用ipcrm
清理不再使用的段是良好的系统管理实践。 - 系统限制: 了解系统对共享内存的限制 (
ipcs -m -l
) 对于设计和调试使用共享内存的应用程序很重要。 key
的转换: 使用ipcrm -M
时,注意ipcs
输出的key
是十六进制,而ipcrm -M
接受十六进制(带0x
)或十进制。使用十六进制格式0x...
最不容易出错。- 替代方案: POSIX 共享内存 (
shm_open
,mmap
) 是现代 Linux 上另一种共享内存机制,通常通过挂载在/dev/shm
下的文件进行操作(使用ls
,rm
等普通文件命令管理)。本文主要讲解传统的 System V 共享内存。