我正在尝试找出如何在 Mac 上重新映射内存映射文件(当我想扩展可用空间时)。
我看到Linux世界的朋友有
mremap
,但我在我的Mac上的标题中找不到这样的功能。 /Developer/SDKs/MacOSX10.6.sdk/usr/include/sys/mman.h
具有以下特点:
mmap
mprotect
msync
munlock
munmap
mremap
man mremap
证实了我的恐惧。
如果我想调整映射文件的大小,我目前必须
munmap
和 mmmap
,这涉及使所有加载的页面无效。一定会有更好的办法。当然可以吗?
我正在尝试编写可在 Mac OS X 和 Linux 上运行的代码。如果我有的话,我可以选择一个宏来在每种情况下使用最好的函数,但我宁愿正确地执行它。
如果需要缩小地图,只需
munmap
要删除末尾的部分即可。
如果您需要放大地图,您可以使用
mmap
MAP_FIXED
到旧地图上方的地址进行适当的偏移,但您需要小心,不要映射到已经存在的其他内容上。 ..上面的删除线文本是一个糟糕的主意;
MAP_FIXED
从根本上来说是错误的,除非您已经知道目标地址上有什么并且想要自动替换它。如果您在地址范围空闲的情况下尝试机会性地映射新内容,则需要将 mmap
与请求的地址一起使用,但 不使用 MAP_FIXED
并查看是否成功并为您提供所请求的地址;如果成功但使用不同的地址,您将需要取消映射刚刚创建的新映射,并假设无法在请求的地址进行分配。
如果您扩展足够大的块(例如,64 MB,但这取决于它增长的速度),那么使旧地图失效的成本可以忽略不计。一如既往,在假设问题之前进行基准测试。
您可以将文件截断为大尺寸(创建一个洞)并映射所有文件。如果文件是持久的,我建议使用写入调用来填充漏洞,而不是通过写入映射来填充,否则文件的块可能会在磁盘上产生不必要的碎片。
我没有内存映射经验,但看起来您可以临时将同一个文件映射两次,作为扩展映射而不丢失任何内容的方法。
int main() {
int fd;
char *fp, *fp2, *pen;
/* create 1K file */
fd = open( "mmap_data.txt", O_RDWR | O_CREAT, 0777 );
lseek( fd, 1000, SEEK_SET );
write( fd, "a", 1 );
/* map and populate it */
fp = mmap( NULL, 1000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
pen = memset( fp, 'x', 1000 );
/* expand to 8K and establish overlapping mapping */
lseek( fd, 8000, SEEK_SET );
write( fd, "b", 1 );
fp2 = mmap( NULL, 7000, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0 );
/* demonstrate that mappings alias */
*fp = 'z';
printf( "%c ", *fp2 );
/* eliminate first mapping */
munmap( fp, 1000 );
/* populate second mapping */
pen = memset( fp2+10, 'y', 7000 );
/* wrap up */
munmap( fp2, 7000 );
close( fd );
printf( "%d\n", errno );
}
输出是
zxxxxxxxxxyyyyyy....
。
我想,如果你继续这样做,可能会比使用
mremap
更快地耗尽地址空间。但无论如何都无法保证,但另一方面它也可能同样安全。
你可以看看 mach_vm_remap