You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 03:36:04