在 Linux 面试中,IPC(进程间通信)是一个高频考点。管道、消息队列、信号量、套接字、共享内存……这些名词你大概都能说上来,但当面试官追问“为什么共享内存是最快的 IPC”以及“shmget 和 mmap 到底怎么选”时,很多人就开始含糊了。这篇文章就把这两个问题彻底讲清楚。
一、先回顾:Linux 有哪些 IPC 方式
常见的 IPC 手段大致可以分成几类:
- 管道(pipe / FIFO):半双工,数据在内核缓冲区中流转,适合父子进程或简单场景。
- 消息队列(System V / POSIX):内核维护队列,有边界和类型,适合结构化消息。
- 信号量(semaphore):主要用于同步,不传输数据。
- 信号(signal):异步通知,信息量极小。
- 套接字(socket):可用于本机或跨主机,通用但开销较大。
- 共享内存(shared memory):多个进程映射同一块物理内存,直接读写。
在这些方式中,共享内存通常被认为是最快的。原因并不神秘,关键在于“数据拷贝次数”。
二、为什么共享内存是最快的 IPC
要理解这个问题,先看其他 IPC 的数据流动路径。
以管道为例,进程 A 要发数据给进程 B,大致经历:
- A 把数据从用户空间拷贝到内核缓冲区;
- 内核把数据从缓冲区拷贝到 B 的用户空间。
也就是说,一次通信至少发生两次数据拷贝,而且还要经历系统调用、上下文切换、内核态与用户态之间的往返。消息队列、套接字在本机通信时也类似,数据都要“绕一圈”内核。
共享内存则完全不同:
- 内核在物理内存中分配一块区域;
- 进程 A 和进程 B 通过页表把这块同一物理内存映射到各自的虚拟地址空间;
- A 写入数据,B 直接就能看到,不需要任何数据拷贝。
用一句话总结:共享内存把“通信”变成了“访问同一块内存”。它省掉了两次拷贝,也省掉了大部分内核参与的数据搬运,所以速度最快。
但要注意,共享内存快,不代表它“省事”。它本身不提供同步机制。多个进程同时读写同一块内存,很容易出现竞态条件。因此实际使用中,共享内存几乎总是和信号量、互斥锁、文件锁等同步手段配合使用。面试时如果只答“快”,不答“需要自己同步”,会被认为理解不完整。
三、shmget 与 mmap:两种共享内存的路线
Linux 下实现共享内存主要有两条路线:
- System V 共享内存:
shmget+shmat+shmdt+shmctl。 - POSIX 共享内存 / 内存映射:
mmap(配合shm_open或普通文件)。
它们底层都依赖同一套虚拟内存映射机制,但接口风格、生命周期和管理方式差别很大。
1. System V 共享内存(shmget)
典型调用流程:
key_t key = ftok("/tmp", 'A');
int shmid = shmget(key, SIZE, IPC_CREAT | 0666);
void *ptr = shmat(shmid, NULL, 0);
// 读写 ptr ...
shmdt(ptr);
shmctl(shmid, IPC_RMID, NULL);
特点:
- 使用 key 标识,适合无亲缘关系进程通过约定 key 找到同一块内存。
- 生命周期由内核管理,除非显式删除或系统重启,否则一直存在。
- 有
shmctl可以查询状态、设置权限、删除。 - 属于较老的 System V IPC 体系,接口偏“重”。
2. mmap 内存映射
mmap 可以把文件或匿名内存映射到进程地址空间。用于共享内存时常见两种形式:
(1)MAP_SHARED + 文件
int fd = open("/tmp/shmfile", O_RDWR | O_CREAT, 0666);
ftruncate(fd, SIZE);
void *ptr = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
(2)POSIX 共享内存 + mmap
int fd = shm_open("/myshm", O_CREAT | O_RDWR, 0666);
ftruncate(fd, SIZE);
void *ptr = mmap(NULL, SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
特点:
- 以文件描述符为中心,和 Linux “一切皆文件”的哲学一致。
- 可以用
open/shm_open打开,用close/shm_unlink管理生命周期。 - 支持
MAP_SHARED和MAP_PRIVATE,还能做文件映射、匿名映射。 - 更现代,接口更统一,和文件 I/O、
read/write能自然衔接。
四、shmget 与 mmap 怎么选
面试中回答这个问题,建议从以下几个维度展开。
1. 生命周期管理
- shmget:内核持久存在,需要
shmctl(IPC_RMID)显式删除,容易残留。 - mmap + 文件/shm_open:可以像文件一样
unlink,引用计数归零后自动释放,管理更直观。
2. 接口风格与可移植性
- shmget:System V IPC,历史悠久,很多老系统和教材都在用,但接口相对笨重。
- mmap:POSIX 风格,更现代,和文件 I/O 结合紧密,可移植性和一致性更好。
3. 使用场景
- 如果只是两个无亲缘关系进程通过约定 key 共享一块内存,且代码风格偏传统,
shmget够用。 - 如果需要和文件映射统一处理、希望生命周期更可控、或者想用
shm_open这种 POSIX 接口,优先选mmap。 - 如果要做大文件映射、按需分页、写时复制,
mmap几乎是唯一自然的选择。
4. 性能
两者底层都是同一块物理内存映射,纯读写性能没有本质差异。差别主要在接口开销、生命周期管理和使用便利性上。所以面试时不要简单说“mmap 更快”,而应该说“性能接近,选择主要看接口、生命周期和场景”。
5. 同步问题
无论选哪种,共享内存本身都不带同步。都需要配合同步原语:
- System V 场景常用 System V 信号量;
- POSIX 场景常用
sem_open、pthread_mutex(配合PTHREAD_PROCESS_SHARED)或文件锁。
五、面试答题模板
如果面试官问“共享内存为什么最快,shmget 和 mmap 怎么选”,可以这样组织回答:
- 先说结论:共享内存最快,因为它把通信变成访问同一块物理内存,省掉了用户态和内核态之间的两次数据拷贝。
- 再说代价:它不提供同步,必须自己配信号量或互斥锁。
- 再对比实现:
shmget是 System V 路线,key 标识、内核持久、需显式删除;mmap是 POSIX 路线,fd 标识、生命周期像文件、更现代。 - 最后说选择:性能接近,选型看生命周期管理、接口风格和场景;要现代、可控选
mmap,要传统、约定 key 选shmget。
把这四点讲清楚,基本就能覆盖面试官想考察的知识点,也能体现出你对 IPC 机制的理解深度。
未经允许不得转载:任鹏个人博客 » Linux 面试中共享内存为什么是最快的 IPC,shmget 与 mmap 怎么选

