将文件映射到内存并写入文件末尾
Mapping file into memory and writing beyong end of file
我正在试验 Linux 中的内存映射文件,并且有一个问题,即从不同进程映射同一文件并写入超出文件末尾时实际发生了什么。
我用 vim 手动创建了一个文件,并在其中写入了 2 个字节:
$ cat test_mmap
aa
然后我写了2个很简单的程序。
第一个程序映射文件并修改映射没有msync
和munmap
。
writer.c
:
int main(void){
int fd = open("/tmp/test_mmap", O_CREAT | O_RDWR, S_IRWXU);
char *mapped_region = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_WRITE, MAP_SHARED, fd, 0);
mapped_region[0] = '0';
mapped_region[1] = '1';
mapped_region[2] = '2';
mapped_region[3] = '3';
mapped_region[4] = '4';
mapped_region[5] = '5';
}
第二个正在读取映射。
reader.c
:
int main(void){
int fd = open("/tmp/test_mmap", O_CREAT | O_RDWR, S_IRWXU);
char *mapped_region = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_WRITE, MAP_SHARED, fd, 0);
printf("%c\n", mapped_region[0]);
printf("%c\n", mapped_region[1]);
printf("%c\n", mapped_region[2]);
printf("%c\n", mapped_region[3]);
printf("%c\n", mapped_region[4]);
printf("%c\n", mapped_region[5]);
}
所以我运行
$ ./writer && ./reader && cat /tmp/test/test_mmap
0
1
2
3
4
5
012
这意味着任何超出文件末尾写入的数据都会在映射中保留一段时间(尽管它没有写出到文件中),如果另一个进程因此映射同一区域,则写入超出的数据不会按照 man-page:
中的指定归零
A file is mapped in multiples of the page size. For a file that is not
a multiple of the page size, the remaining memory is zeroed when
mapped, and writes to that region are not written out to the file.
运行 reader 和 perf -e major-faults ./reader
表示
0 major-faults
表示没有从磁盘读取任何页面。同时查看 /proc/<pid_writer>/smaps
我观察到该页面被标记为脏和私有(即使映射是使用 MAP_SHARED
标志创建的):
7fc80f279000-7fc80f27a000 -w-s 00000000 fd:00 6057290 /tmp/test_mmap
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
如果我 运行 reader 处理一段时间后(需要等待什么时间?)我观察到
$ ./reader
0
1
2
问题:是否正确并在某处记录了如果一个进程修改了超出文件末尾的映射,则页面被标记为dirty 只要页面是脏的并且另一个进程映射同一个文件的相同区域,进程之前写入的数据就不会被清零并保留一段时间?
这些问题的权威参考是POSIX,它在mmap的基本原理部分必须说:
The mmap() function can be used to map a region of memory that is
larger than the current size of the object. [... snip discussion on
sending SIGBUS if possible, i.e. when accessing a page beyond the end
of the file ...] written data may be lost and read data may not
reflect actual data in the object.
所以,POSIX 说这样做会导致数据丢失。此外,可移植性充其量也值得怀疑(想想 no-MMU 系统、与大页面的交互、具有不同页面大小的平台...)
我正在试验 Linux 中的内存映射文件,并且有一个问题,即从不同进程映射同一文件并写入超出文件末尾时实际发生了什么。
我用 vim 手动创建了一个文件,并在其中写入了 2 个字节:
$ cat test_mmap
aa
然后我写了2个很简单的程序。
第一个程序映射文件并修改映射没有msync
和munmap
。
writer.c
:
int main(void){
int fd = open("/tmp/test_mmap", O_CREAT | O_RDWR, S_IRWXU);
char *mapped_region = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_WRITE, MAP_SHARED, fd, 0);
mapped_region[0] = '0';
mapped_region[1] = '1';
mapped_region[2] = '2';
mapped_region[3] = '3';
mapped_region[4] = '4';
mapped_region[5] = '5';
}
第二个正在读取映射。
reader.c
:
int main(void){
int fd = open("/tmp/test_mmap", O_CREAT | O_RDWR, S_IRWXU);
char *mapped_region = mmap(NULL, sysconf(_SC_PAGESIZE), PROT_WRITE, MAP_SHARED, fd, 0);
printf("%c\n", mapped_region[0]);
printf("%c\n", mapped_region[1]);
printf("%c\n", mapped_region[2]);
printf("%c\n", mapped_region[3]);
printf("%c\n", mapped_region[4]);
printf("%c\n", mapped_region[5]);
}
所以我运行
$ ./writer && ./reader && cat /tmp/test/test_mmap
0
1
2
3
4
5
012
这意味着任何超出文件末尾写入的数据都会在映射中保留一段时间(尽管它没有写出到文件中),如果另一个进程因此映射同一区域,则写入超出的数据不会按照 man-page:
中的指定归零A file is mapped in multiples of the page size. For a file that is not a multiple of the page size, the remaining memory is zeroed when mapped, and writes to that region are not written out to the file.
运行 reader 和 perf -e major-faults ./reader
表示
0 major-faults
表示没有从磁盘读取任何页面。同时查看 /proc/<pid_writer>/smaps
我观察到该页面被标记为脏和私有(即使映射是使用 MAP_SHARED
标志创建的):
7fc80f279000-7fc80f27a000 -w-s 00000000 fd:00 6057290 /tmp/test_mmap
Shared_Clean: 0 kB
Shared_Dirty: 0 kB
Private_Clean: 0 kB
Private_Dirty: 4 kB
如果我 运行 reader 处理一段时间后(需要等待什么时间?)我观察到
$ ./reader
0
1
2
问题:是否正确并在某处记录了如果一个进程修改了超出文件末尾的映射,则页面被标记为dirty 只要页面是脏的并且另一个进程映射同一个文件的相同区域,进程之前写入的数据就不会被清零并保留一段时间?
这些问题的权威参考是POSIX,它在mmap的基本原理部分必须说:
The mmap() function can be used to map a region of memory that is larger than the current size of the object. [... snip discussion on sending SIGBUS if possible, i.e. when accessing a page beyond the end of the file ...] written data may be lost and read data may not reflect actual data in the object.
所以,POSIX 说这样做会导致数据丢失。此外,可移植性充其量也值得怀疑(想想 no-MMU 系统、与大页面的交互、具有不同页面大小的平台...)