9

我有以下问题:

mmap我通过with分配了一大块内存(多个 GiB)MAP_ANONYMOUS。该块包含一个大的哈希映射,需要不时将其归零。不是每一轮都可以使用整个映射(不是每个页面都出错),所以memset不是一个好主意 - 需要太长时间。

快速执行此操作的最佳策略是什么?

将要

madvise(ptr, length, MADV_DONTNEED);

向我保证任何后续访问都会提供新的空白页面?

从 Linuxman madvise页面:

此调用不会影响应用程序的语义(除了MADV_DONTNEED的情况),但可能会影响其性能。内核可以随意忽略这些建议。

...

MADV_DONTNEED

对该范围内的页面的后续访问将成功,但将导致从底层映射文件(请参阅 mmap(2))重新加载内存内容或零填充按需页面以用于没有底层文件的映射。

...

当前的 Linux 实现(2.4.0)将此系统调用更多地视为命令而不是建议......

还是我必须munmap重新映射该区域?

它必须在 Linux 上工作,并且理想情况下在 OS X 上具有相同的行为。

4

3 回答 3

9

对于您的问题,有一个更简单的解决方案,它相当便携:

mmap(ptr, length, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);

由于MAP_FIXED允许由于相当任意的特定于实现的原因而失败,因此建议memset返回是否返回。MAP_FAILED

于 2013-09-03T16:18:37.510 回答
2

在 Linux 上,您可以依靠MADV_DONTNEED匿名映射将映射归零。不过,这不是可移植的——madvise()它本身并没有标准化。 posix_madvise()是标准化的,但与Linux标志的行为不同-始终是建议性的,不会影响应用程序的语义POSIX_MADV_DONTNEEDMADV_DONTNEEDposix_madvise()

于 2013-09-04T01:48:12.767 回答
1

这种madvise行为当然不是标准的,所以这不是可移植的。

如果您想要归零的部分恰好位于映射的末尾,您可以侥幸逃脱ftruncate。您必须再介绍一步:

  1. shm_open为您的数据提供“持久”文件描述符
  2. ftruncate到需要的大小
  3. mmap那个FD

那么你总是可以

  1. munmap
  2. ftruncate简短的
  3. ftruncate到你需要的真实长度
  4. mmap再次

然后您“重新映射”的部分将被初始化为零。

但也要记住,系统必须对页面进行归零。这可能比编译器为 生成的内联内容更有效memset,但这并不确定。

于 2013-09-03T16:01:34.600 回答