使用shm_open和ftruncate分配的Linux共享内存大小不符合设定原因
共享内存大小不符问题解答
测试代码与场景
为测试Linux系统的共享内存机制,编写了如下测试代码:
#include <sys/types.h> #include <sys/mman.h> #include <err.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(void) { const char str1[] = "string 1"; const char str2[] = "string 2"; pid_t parpid = getpid(), childpid; int fd = -1; char *anon, *zero; if((fd = shm_open("/mmap_test", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR)) == -1) err(1, "shm_open"); printf("created shared memory file\n"); if(ftruncate(fd, 1024) != 0) err(1,"ftruncate"); anon = (char*)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); zero = (char*)mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (anon == MAP_FAILED) errx(1, "anon mmap"); if (zero == MAP_FAILED) errx(1, "zero mmap"); strcpy(anon, str1); strcpy(zero, str1); printf("PID %d:\tanonymous %s, zero-backed %s\n", parpid, anon, zero); switch ((childpid = fork())) { case -1: err(1, "fork"); /* NOTREACHED */ case 0: childpid = getpid(); printf("PID %d:\tanonymous %s, zero-backed %s\n", childpid, anon, zero); sleep(3); printf("PID %d:\tanonymous %s, zero-backed %s\n", childpid, anon, zero); munmap(anon, 4096); munmap(zero, 1024); close(fd); return EXIT_SUCCESS; } sleep(2); strcpy(anon, str2); strcpy(zero, str2); printf("PID %d:\tanonymous %s, zero-backed %s\n", parpid, anon, zero); munmap(anon, 4096); munmap(zero, 1024); sleep(3); close(fd); return EXIT_SUCCESS; }
编译命令:
g++ -lpthread -lrt mmap_test.cpp
问题描述
代码中通过shm_open创建名为/mmap_test的共享内存对象,调用ftruncate将其大小设置为1024字节,再通过mmap映射1024字节的共享空间。修改ftruncate入参设置不同的共享内存大小后,使用ls -sh /dev/shm/mmap_test命令查看生成的共享内存文件,发现其大小始终为4.0KB,和Linux系统页大小一致,为什么实际分配的共享内存大小不符合代码中设置的数值?
原因说明
- 首先要区分两个完全不同的指标:
- 文件逻辑大小:使用
ls -l /dev/shm/mmap_test查看的数值就是你通过ftruncate设置的1024字节,这个完全符合代码配置。 - 实际占用内存块大小:你用
ls -sh看到的4KB是文件实际占用的内存空间,这个数值和逻辑大小不一致是Linux内存管理的正常特性。
- 文件逻辑大小:使用
- Linux内核的内存分配以*页(Page)*为最小单位,绝大多数x86架构Linux系统的默认页大小是4KB,你可以通过
getconf PAGE_SIZE命令查看当前系统的页大小。 - 共享内存基于内存页实现,同时
/dev/shm挂载的是tmpfs文件系统,所有文件的实际占用空间都会向上对齐到页大小的整数倍:哪怕逻辑大小只有1字节,只要对这块共享内存做了写入操作,内核就会至少分配1个完整的页来存储数据,所以实际占用的内存块大小最小就是4KB。如果设置的逻辑大小超过4KB,比如5000字节,实际就会占用2个页共8KB的内存空间。 - 你可以用
stat /dev/shm/mmap_test命令验证这个结论:输出中的Size字段会显示你设置的逻辑大小1024字节,Blocks字段会显示为8(每个统计块默认是512字节,8*512=4096字节即4KB),正好对应实际占用的内存大小。
内容的提问来源于stack exchange,提问作者Ziqi Fan
相关产品推荐
相关产品推荐

