当mmap()请求映射尺寸大于文件时的预期行为探究
mmap映射超出文件大小区域的行为分析
用户给出的mmap使用示例:
// 假设 PAGE_SIZE == 4096 int fd = open("/some/large/resource", O_RDONLY); void *buffer = mmap(NULL, 8192, PROT_READ, MAP_SHARED, fd, 0); // 使用buffer munmap(buffer, 8192);
对应的read实现示例:
int fd = open("/some/large/resource", O_RDONLY); void *buffer = malloc(8196); read(fd, buffer, 8196); // 使用buffer free(buffer);
当前场景:目标文件/some/large/resource实际大小为4096字节(一页),但mmap尝试映射8192字节(两页),以下分析两种方式的差异及mmap不同flag下的行为:
read方式的表现
调用read后,会返回实际读取的4096字节,malloc分配的缓冲区中未被填充的剩余部分(4096-8195字节)是未初始化内存,值不确定,但可正常写入。
mmap的行为(按flag分类)
MAP_SHARED 模式
- mmap调用本身不会报错,内核允许创建超出文件大小的映射区域。
- 当访问超出文件大小的那一页(即4096-8191字节范围)时,会触发SIGBUS信号,直接导致程序崩溃。原因是MAP_SHARED要求映射区域与原文件同步,但原文件以O_RDONLY打开,无法扩展来容纳超出的页,内核无法完成映射页与文件的关联,因此触发总线错误。
MAP_PRIVATE 模式
- mmap调用同样不会报错。
- 访问超出文件大小的那一页时,内核会自动分配一块私有匿名页,并将其初始化为0。此时读取这部分内存会得到全0值;如果映射时设置了PROT_WRITE权限,写入这部分只会修改私有页,不会影响原文件。
核心差异总结
- 映射超出文件大小的区域时,mmap本身不会失败,行为差异体现在实际访问超出区域时。
- MAP_SHARED下访问超出区域(只读文件场景)会触发SIGBUS;MAP_PRIVATE下会得到初始化为0的私有页,可安全访问。
- 与read方式的区别:read的剩余缓冲区是未初始化的垃圾值,而mmap在MAP_PRIVATE下超出部分是0,MAP_SHARED下直接触发错误。
内容的提问来源于stack exchange,提问作者CPlus
相关产品推荐
相关产品推荐

