madvise(___, ___, MADV_DONTNEED) 是否指示操作系统延迟写入磁盘?

问题描述 投票:0回答:4

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

如果我 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
4个回答
23
投票

不!

为了你好,请远离

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
,否则您会
MADV_DONTNEED而丢失数据。如果您无法承受可能的阻塞,那么遗憾的是您别无选择,只能在另一个线程中执行此操作。

对于最新的 Linux 内核(刚刚在 Linux 5.4 上测试),当映射为

4
投票
时,

MADV_DONTNEED

 可以按预期工作,例如
mmap 没有 MAP_PRIVATE
 标志。我不确定以前版本的 Linux 内核的行为是什么。
从 Linux 手册页项目的 
madvise

手册页 4.15 版本开始:

成功执行 

MADV_DONTNEED
操作后,指定区域中内存访问的语义将发生更改:该范围内页面的后续访问将成功,但会导致

从最新内容重新填充内存内容底层映射文件(用于共享文件映射、共享匿名映射和基于 shmem 的技术,例如 System V 共享内存段)

 或用于匿名私有映射的按需填零页面。
Linux 添加了一个新标志

MADV_FREE
,与

Linux 4.5 中的 BSD 系统具有相同的行为



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

为什么私有映射的

MADV_DONTNEED
可能会导致将来访问时页面填充为零,请观看 @Damon 答案的评论中提到的

Bryan Cantrill 的咆哮

。剧透:
它来自 Tru64 UNIX

正如已经提到的,

2
投票
不是你的朋友。从 Linux 5.4 开始,您可以使用

MADV_COLD

 告诉内核在存在内存压力时应该调出该内存。这似乎正是这种情况下想要的。
在这里阅读更多内容:
https://lwn.net/Articles/793462/

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

0
投票

© www.soinside.com 2019 - 2024. All rights reserved.