我正在尝试使用 MAP_SHARED 创建内存映射文件。当文件大小达到 2gb 时,我遇到了问题。下面粘贴的代码是我正在使用的(作为测试)。
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#define MY_FILE "/dev/shm/mmap_test"
#define BLOCK_SIZE (1024*1024)
#define NUM_FILES 1
void mk_file(int f_num)
{
uint64_t len = 0;
int fd, j, k;
char tmp_file[1024], *x, *rr_addr;
// Open file in /dev/shm
sprintf(tmp_file, "%s%d", MY_FILE, f_num);
fd = open(tmp_file, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
if (fd == -1)
{
perror("file open");
exit(-1);
}
// 16Gb file
len = 16UL * 1024 * 1024 * 1024;
printf("len: %ld Gb\n", len/(1024*1024*1024));
printf("Mapping %ld blocks\n", len/BLOCK_SIZE);
for (j = 0; j < len/BLOCK_SIZE; j++) {
// Increase the file size
ftruncate(fd, ((j + 1) * BLOCK_SIZE));
// Just mmap memory... don't have file backing
//rr_addr = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE|MAP_NORESERVE, -1, 0);
// MMAP a region to the file at a given offset
rr_addr = mmap(NULL, BLOCK_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_NORESERVE, fd, (j * BLOCK_SIZE));
if (rr_addr == MAP_FAILED) {
perror("mmap error");
printf("INDEX: %d\n", j);
exit(-1);
}
// Write to every byte of allocated memory
x = (char *) rr_addr;
for (k = 0; k < BLOCK_SIZE; k++)
{
*x = '1';
x++;
}
}
return;
}
int main(int argc, char **argv)
{
uint64_t i;
for (i = 0; i < NUM_FILES; i++)
mk_file(i);
return 0;
}
在上面的代码中,当文件中的偏移量达到 2gb 时出现总线错误。这些是我尝试过的事情:
- 如果我将 NUM_FILES 更改为 16 并将 len 更改为 1GB,我没有任何问题。
- 如果我删除写入内存的 for 循环(仅 mmap),程序不会崩溃(即使 len 远大于 2gb)b/c linux 内核实际上不会将页面映射到文件,直到你读/写到映射的区域。
- 如果我将 mmap 调用从 MAP_SHARED 更改为 MAP_ANON(取消注释第一个 mmap 调用并注释掉第二个)并且未链接到文件,则没有问题(即使写入成功)。
- /dev/shm (30gb) 上有足够的空间,我这里只用了 16gb。
- 我不必写入每个分配的字节。我只需要写入最后一个 mmap'ed 区域(将内部 for 循环移到外面),如果偏移量 + BLOCK_SIZE >= 2gb 则出现总线错误。
- 我已经在 Ubuntu 13.10 和 CentOS 6.4 上尝试过,两者都有同样的问题。
我想知道这是否是linux内核中的问题?有没有人尝试过使用大于 2gb 的 MAP_SHARED 映射单个文件并成功使用(读/写)它?