我正在尝试找出如何在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的代码。如果我有,我可以选择使用宏来使用最佳功能,但我宁愿正确使用。
答案 0 :(得分:5)
如果您需要缩小地图,只需munmap
您想要移除的部分。
如果您需要放大地图,可以 mmap
使用MAP_FIXED
正确偏移旧地图上方的地址,但是您需要注意不要映射已存在的其他内容......
在三振出局下的上述文字是一个糟糕的主意; MAP_FIXED
基本上是错误的,除非您已经知道目标地址的内容并希望以原子方式替换它。如果您尝试在地址范围空闲的情况下机会性地映射新内容,则需要使用mmap
一个请求的地址,但没有 MAP_FIXED
,看看它是否成功并给出你要求的地址;如果它成功但使用不同的地址,您将要取消映射刚刚创建的新映射,并假设无法在请求的地址进行分配。
答案 1 :(得分:1)
如果扩展到足够大的块(例如,64 MB,但它取决于它的增长速度),那么使旧地图无效的成本可以忽略不计。和往常一样,在假设问题之前进行基准测试。
答案 2 :(得分:0)
我没有内存映射的经验,但看起来你可以暂时映射同一个文件两次,以扩展映射而不会丢失任何内容。
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
更快地耗尽地址空间。但无论如何都没有任何保证,另一方面它可能同样安全。
答案 3 :(得分:0)
您可以将文件设置为大尺寸(创建一个孔)并将其全部映射到mmap。如果文件是持久性的,我建议使用写入调用来填充漏洞,而不是通过写入映射,否则文件的块可能会在磁盘上被不必要地分段。