【问题标题】:Does madvise(___, ___, MADV_DONTNEED) instruct the OS to lazily write to disk?madvise(___, ___, MADV_DONTNEED) 是否指示操作系统延迟写入磁盘?
【发布时间】:2013-02-04 18:33:04
【问题描述】:

假设我想对一个可能非常大的文件执行顺序写入。

如果我 mmap() 一个巨大的区域并在整个区域上进行 madvise(MADV_SEQUENTIAL),那么我可以以相对有效的方式写入内存。我已经可以正常工作了。

现在,为了在我编写时释放各种操作系统资源,我偶尔会在已写入的小块内存上执行 munmap()。我担心 munmap() 和 msync() 会阻塞我的线程,等待数据物理提交到磁盘。我一点都不能放慢我的写作速度,所以我需要另辟蹊径。

在已经写入的小块内存上使用 madvise(MADV_DONTNEED) 会更好吗?我想告诉操作系统将内存延迟写入磁盘,而不是阻塞我的调用线程。

madvise() 的手册页有这样的说法,这是相当模棱两可的:

MADV_DONTNEED
Do  not expect access in the near future.  (For the time being, the 
application is finished with the given range, so the kernel can free
resources associated with it.)  Subsequent accesses of pages in this
range will succeed, but will result either in re-loading  of the memory
contents from the underlying mapped file (see mmap(2)) or
zero-fill-on-demand pages for mappings without an underlying file.

【问题讨论】:

标签: linux linux-kernel kernel shared-memory mmap


【解决方案1】:

首先,madv_sequential 启用主动预读,因此您不需要它。 其次,os 无论如何都会懒惰地将脏的文件烘焙内存写入磁盘,即使你什么也不做。但是 madv_dontneed 会指示它立即释放内存(你称之为“各种操作系统资源”)。第三,不清楚顺序写入的映射文件有什么优势。仅 write(2) 可能会更好地为您服务(但使用缓冲区 - 手动或 stdio)。

【讨论】:

  • 这个答案是错误的,原因见上面的答案。
【解决方案2】:

不!

为了你好,远离MADV_DONTNEED。 Linux 将不会将此作为在写回页面后将其丢弃的提示,而是立即将其丢弃。这不是一个错误,而是一个深思熟虑的决定。

具有讽刺意味的是,原因是非破坏性MADV_DONTNEED 的功能已经由msync(MS_INVALIDATE|MS_ASYNC) 提供,另一方面,MS_ASYNC 不会启动 I/O(实际上,它什么都不做,遵循脏页写回无论如何都可以正常工作的推理),fsync 总是阻塞,sync_file_range 可能会阻塞如果你超过了一些模糊的限制并且被文档认为是“极其危险”,无论如何意思。

无论哪种方式,您都必须在msync(MS_SYNC)fsync(都阻塞)或sync_file_range(可能阻塞)后跟fsync,否则您丢失@987654333 的数据@。如果您无法承受阻塞,那么遗憾的是,您别无选择,只能在另一个线程中执行此操作。

【讨论】:

【解决方案3】:

对于最近的 Linux 内核(刚刚在 Linux 5.4 上测试过),MADV_DONTNEED 在映射为非私有时按预期工作,例如mmap 没有 MAP_PRIVATE 标志。我不确定以前版本的 Linux 内核的行为是什么。

从 Linux 手册页项目的 madvise 手册页的 4.15 版开始:

MADV_DONTNEED操作成功后,指定区域内存访问的语义发生变化:后续访问该范围内的页面会成功,但会导致重新填充内存内容- 底层映射文件的日期内容(用于共享文件映射、共享匿名映射和基于 shmem 的技术,例如 System V 共享内存段)或用于匿名私有映射的按需零填充页面。

Linux 在 Linux 4.5 中添加了一个新标志 MADV_FREE,在 BSD 系统中具有相同的行为

它只是将页面标记为可在需要时释放,但它不会立即释放它们,从而可以重用内存范围而不会产生再次出错页面的成本。

关于为什么MADV_DONTNEED 用于私有映射可能会在将来访问时导致零填充页面,请观看@Damon 的答案中提到的Bryan Cantrill's rant。剧透:它来自 Tru64 UNIX。

【讨论】:

    【解决方案4】:

    如前所述,MADV_DONTNEED 不是你的朋友。从 Linux 5.4 开始,您可以使用MADV_COLD 告诉内核它应该在存在内存压力时分页该内存。这似乎正是在这种情况下想要的。

    在这里阅读更多: https://lwn.net/Articles/793462/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-08-30
      • 1970-01-01
      • 2020-03-14
      • 1970-01-01
      • 2011-10-10
      • 1970-01-01
      • 2012-01-15
      相关资源
      最近更新 更多