我有以下问题:
我通过mmap
与MAP_ANONYMOUS
分配了一大块内存(多个GiB)。该块包含一个大的哈希映射,需要时不时地归零。并非整个映射可以在每一轮中使用(并非每个页面都有错误),因此memset
不是一个好主意 - 需要太长时间。
快速完成此任务的最佳策略是什么?
将
madvise(ptr, length, MADV_DONTNEED);
保证我后续的任何访问都会提供新的空页?
来自Linux man madvise
页面:
此调用不会影响应用程序的语义( MADV_DONTNEED 除外),但可能会影响其性能。内核可以自由地忽略这些建议。
...
MADV_DONTNEED
此范围内页面的后续访问将成功,但会导致从底层映射文件重新加载内存内容(请参阅mmap(2))或零填充按需页面以获取没有基础文件的映射
...
当前的Linux实现(2.4.0)将此系统调用视为命令而不是建议......
或者我是否需要munmap
并重新重新映射该区域?
它必须在Linux上工作,理想情况下在OS X上具有相同的行为。
答案 0 :(得分:8)
对于您的问题,有一个更容易解决的问题是相当便携:
mmap(ptr, length, PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
由于MAP_FIXED
被允许因相当任意的特定于实现的原因而失败,因此如果返回memset
,则回到MAP_FAILED
是明智的。
答案 1 :(得分:1)
这种madvise
行为当然不是标准行为,因此不可移植。
如果您想要归零的部分恰好位于映射的末尾,则可以使用ftruncate
。你必须再介绍一步:
shm_open
为您的数据提供“持久”文件描述符ftruncate
达到所需的尺寸mmap
的FD 然后你总是可以
munmap
ftruncate
简短ftruncate
到你需要的实际长度mmap
再次然后你“重新映射”的部分将被初始化为零。
但是还要记住,系统必须对页面进行归零。这可能比编译器为memset
生成的内联函数更有效,但这不确定。
答案 2 :(得分:1)
在Linux上,您可以依赖MADV_DONTNEED
对映射进行归零的匿名映射。但这并不便携 - madvise()
本身并未标准化。 posix_madvise()
是标准化的,但POSIX_MADV_DONTNEED
不与Linux MADV_DONTNEED
标志具有相同的行为 - posix_madvise()
始终是建议性的,而不是影响应用程序的语义。