我正在写很多很多的数据,这些数据在几个星期内不会被再次读取 – 因为我的程序在机器上运行的可用内存量(以“free”或“top”显示)非常快地下降,内存量应用程序使用不会增加 – 其他进程使用的内存量也不会增加。
这使我相信内存正在被文件系统caching消耗 – 因为我不打算长时间读这个数据,所以我希望绕过系统缓冲区,这样我的数据就直接写到磁盘上了。 我没有梦想改善性能或成为一个超级忍者,我的希望是给文件系统一个提示,我不会马上回来这个内存,所以不花时间优化这些情况。
在Windows上,我遇到了类似的问题,并使用FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH修复了这个问题 – 机器的内存没有被我的应用程序占用,而且机器通用性更好。 我希望能够复制我在Linux上看到的改进。 在Windows系统中,对于扇区大小的文件是有限制的,所以我很高兴这个限制了我测量的增益。
有没有类似的方式来做到这一点在Linux?
与你所提到的Windows标志最接近的地方,我能想到的是用open(2)
标志打开你的文件O_DIRECT | O_SYNC
O_DIRECT | O_SYNC
:
O_DIRECT (Since Linux 2.4.10) Try to minimize cache effects of the I/O to and from this file. In general this will degrade performance, but it is useful in special situations, such as when applications do their own caching. File I/O is done directly to/from user space buffers. The O_DIRECT flag on its own makes at an effort to transfer data synchronously, but does not give the guarantees of the O_SYNC that data and necessary metadata are transferred. To guarantee synchronous I/O the O_SYNC must be used in addition to O_DIRECT. See NOTES below for further discussion. A semantically similar (but deprecated) interface for block devices is described in raw(8).
当然,试图做这个标志的研究,以确认它是你想要的,我发现这个有趣的一块告诉你,无缓冲I / O是一个坏主意,莱纳斯形容为“脑损伤”。 据说你应该使用madvise()
来告诉内核如何缓存页面。 因人而异。
您可以使用O_DIRECT,但在这种情况下,您需要自己执行块IO; 您必须以FS块大小和块边界的倍数(可能不是强制性的,但是如果不是它的性能会吸取x1000,因为每个未对齐的写操作都需要先读取)。
使用OS高速缓存而不使用O_DIRECT来阻止块的另一个影响更小的方法是使用posix_fadvise(fd,offset,len,POSIX_FADV_DONTNEED)。 在支持它的Linux 2.6内核下,这会立即从缓存中丢弃(清除)数据块。 当然,你需要首先使用fdatasync()或类似的东西,否则块可能仍然是脏的,因此不会从缓存中清除。
在每次写入之后,这可能是fdatasync()和posix_fadvise(… POSIX_FADV_DONTNEED)的一个坏主意,而是等到你做了一个合理的数量(可能是50M,100M)。
所以总之
有些用户已经发现,像快速增长的日志文件这样的东西可以轻易地将“更有用”的东西从磁盘缓存中清除出去,这就减少了需要大量读取缓存的盒子上的缓存命中,而且还快速地写入日志。 这是此功能的主要动机。
但是,像任何优化
a)你不需要这样做
b)不要做(尚)
当我的程序运行在机器上的可用内存量下降得非常快
为什么这是个问题? 可用内存是不起任何有用目的的内存。 当它被用来缓存数据时,至少有可能会有用。
如果你的一个程序请求更多的内存,文件缓存将是第一个要去的地方。 Linux知道它可以随时从磁盘重新读取数据,所以它只会收获内存并给它一个新的使用。
确实,在刷新写入磁盘之前,Linux默认等待约30秒(这是以前的值)。 你可以通过调用fsync()
来加快速度。 但是,一旦数据写入磁盘,将数据缓存保存在内存中几乎没有任何成本。
看到你写入文件并不读取它,Linux可能会猜测这个数据是最好的抛出,而不是其他缓存的数据。 因此,除非您确认这是性能问题,否则不要浪费精力去优化。