15

我正在尝试找出如何在 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 的代码。如果必须,我可以选择一个宏来在每种情况下使用最好的功能,但我宁愿正确地做到这一点。

4

4 回答 4

4

如果您需要缩小地图,只需munmap在最后要删除的部分即可。

如果您需要放大地图,您可以mmap适当偏移MAP_FIXED到旧地图上方的地址,但您需要注意不要映射到已经存在的其他东西......

删除线下的上述文字是一个糟糕的主意;MAP_FIXED除非您已经知道目标地址中的内容并希望以原子方式替换它,否则这从根本上是错误的。如果您试图在地址范围空闲的情况下机会性地映射新的东西,您需要使用mmap请求的地址但没有 MAP_FIXED,看看它是否成功并为您提供请求的地址;如果它成功但使用不同的地址,您将希望取消映射您刚刚创建的新映射并假设无法在请求的地址进行分配。

于 2010-12-29T04:37:59.450 回答
1

如果您扩展足够大的块(例如,64 MB,但这取决于它的增长速度),那么使旧地图失效的成本可以忽略不计。与往常一样,在假设问题之前进行基准测试。

于 2011-04-02T20:33:52.900 回答
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....

我想,如果您对此有所了解,则可能会比 with 更快地耗尽地址空间mremap。但无论哪种方式都无法保证,另一方面它可能同样安全。

于 2010-08-19T19:45:44.703 回答
0

您可以将文件 ftruncate 到一个大尺寸(创建一个洞)并映射所有文件。如果文件是持久的,我建议用写调用而不是通过写入映射来填充漏洞,否则文件的块可能会在磁盘上不必要地碎片化。

于 2010-08-19T21:15:07.333 回答