假设我想对可能非常大的文件执行顺序写入.
如果我在整个区域上mmap()一个巨大的区域和madvise(MADV_SEQUENTIAL),那么我可以以相对有效的方式写入内存.我已经开始工作了.
现在,为了在我编写时释放各种OS资源,我偶尔会在已经写入的小块内存上执行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.
解决方法
没有!
为了您自己的利益,请远离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的数据.如果你不能阻止,你可能别无选择,但要在另一个线程中做到这一点.