我注意到在执行这样的命令后,我遇到了系统响应能力(桌面GUI)的主要问题:
cat file_larger_than_ram.bin | ./simple-process
我的理论是,这会导致Linux内核丢弃目前在RAM未使用部分中保存的文件的缓存。同时,进程需要访问它们所处理的数据,因此在执行上述命令后,它们必须再次加载其文件。鉴于我只使用file_larger_than_ram.bin
一次,有没有办法提示内核不要缓存文件?我听说我可以使用fadvise
,但我不确定fadvise64(2)
说的是什么:
POSIX_FADV_DONTNEED尝试释放与指定区域关联的缓存页面。例如,这很有用 流式传输大文件。程序可以周期性地请求内核 释放已经使用过的缓存数据,以便更有用 不会丢弃缓存页面。
应用fdadvise (input_desc, 0, 0, POSIX_FADV_DONTNEED);
实际上是否符合我的预期并在此处解决问题?
答案 0 :(得分:2)
鉴于我只会使用file_larger_than_ram.bin一次,有没有办法提示内核不要缓存文件?
据我所知,使用O_DIRECT
系统调用的open
标志即可。但是该标志带有额外的限制(例如文件偏移和用户空间内存缓冲区对齐),这可能会导致问题。它们在测试中没有给我带来问题,但是文档说该行为是特定于设备/文件系统的。因此,我将代码更改为使用fadvise()
。
(此外,我观察到一些性能不合规定(read()
/ write()
太快),这表明即使使用O_DIRECT
,某些数据有时也会被缓存.YMMV。)< / p>
我听说我可以使用fadvise,但我不确定[...]
我也不清楚,所以我检查了内核源代码。使用fadvise()
进行POSIX_FADV_DONTNEED
调用的效果是从缓存中删除相应的数据。我还没有看到任何迹象表明该标志是 sticky 并适用于所有文件操作。 (这就是我检查源代码的原因:我知道Linux通过缓存执行I / O 始终,O_DIRECT
可以替代。粘性POSIX_FADV_DONTNEED
没有& #39;适合范式。)
换句话说,要在阅读期间释放缓存,您需要:
在read()
在read()
之后,就您刚刚阅读的数据范围致电fadvise(POSIX_FADV_DONTNEED)
。
为了获得最佳效果,您必须读取页面对齐块中的数据。 I / O缓存是基于页面的,fadvise()
将指定的数据范围映射到页面列表中。错位会导致额外read()
s(和伤害表现),否则无害。
对于写作来说,它有点复杂:我观察到fadvise(POSIX_FADV_DONTNEED)
如果在write()
之后立即调用则无效。必须调用fsync()
/ fdatasync()
来强制写入数据,从而取消固定缓存条目,然后再调用fadvise(POSIX_FADV_DONTNEED)
来释放它们。
P.S。据我了解内核代码,由@AlexHoppus链接的dd
的技巧应该有效。例如cat file; dd if=file of=/dev/null iflag=nocache
- cat
调用会将文件放入缓存中,dd
会从缓存中读取它,然后将其从缓存中丢弃。 fadvise(POSIX_FADV_DONTNEED)
在全局缓存上运行,因此无论是谁/何时读取数据都无关紧要,无论如何都会丢弃它们。