例如。
fd = ::open ("/test.txt", O_RDONLY, 0);
struct stat buf;
fstat(fd, &buf);
char* addr = (char*)::mmap(NULL, buf.st_size + 10, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, 0);
请注意,我在这里映射了+ 10。但它仍然有效吗?
为什么系统不适用任何检查?危险吗?
谢谢
mmap的签名是:
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
引用Michael Kerrisk的话:
length参数指定映射的大小(以字节为单位)。尽管length不需要是系统页面大小的倍数(由sysconf(_SC_PAGESIZE)返回),但内核以此大小为单位创建映射,因此长度实际上会向上舍入到下一个倍数。页面大小。 - Linux编程接口(第49章)
引用Robert Love:
mmap()系统调用在页面上运行。 addr和offset参数都必须在页面大小的边界上对齐。也就是说,它们必须是页面大小的整数倍。因此,映射是页面的整数倍。如果调用者提供的len参数未在页面边界上对齐 - 可能是因为基础文件的大小不是页面大小的倍数 - 映射将向上舍入到下一个整页。此添加的内存中的最后一个有效字节和映射结束之间的字节为零填充。从该区域读取的任何内容都将返回零。对该内存的任何写入都不会影响后备文件,即使它被映射为MAP_SHARED。只有原始的len字节才会被写回文件。 - Linux系统编程(第4章)
我假设您的系统正在运行Linux。一定要阅读intro(2)。
我们可以mmap(2)文件超过它们的大小,因为如果我们不能,只有页面大小的精确倍数的文件(通常是4K字节,可能是1M字节,请参阅sysconf(3)与PAGESIZE
)可以进行内存映射。如果是这种情况,内存映射文件将没那么有用。此外,mmap
文件的大小可能随时间变化(其他过程write(2)ing和附加到它,调用ftruncate(2)等等)所以kernel要求(或强制执行)它是没有意义的不会改变。
仔细阅读mmap(2)的文档,它说:
文件以页面大小的倍数映射。对于不是页面大小倍数的文件,剩余内存在映射时归零,并且写入该区域不会写入文件。
(当然内核正在做一些检查,可能比你想象的要多得多)
和mmap
可能会失败,所以你的代码应该检查,例如,遵循它:
if ((void*)addr == MAP_FAILED)
{ perror("mmap"); exit(EXIT_FAILURE); };
顺便说一下,你的问题不是C ++特定的,而是POSIX或Linux特定的(其他操作系统可能不提供memory mapped files,或者可能对它们施加其他限制)。
请注意,内存映射非常常见。它被mmap
和execve(2)时间使用。您可以通过virtual address space process了解某些给定using的/proc/
(请参阅proc(5)并在终端中尝试cat /proc/self/maps
和cat /proc/$$/maps
)。 mmap
经常使用:malloc(3)和operator new
,dlopen(3),ld-linux(8),动态链接的共享库。
另请阅读一些关于Linux或POSIX编程的书(例如旧的Advanced Linux Programming,可免费下载或更新的东西)和Operating Systems: Three Easy Pieces。