我想知道是否有一种方法可以阻止 Linux 定期将 mmap 文件同步到磁盘,同时仍然允许操作系统在物理内存紧张时回写。
我正在编写处理大图像的应用程序,图像太大以至于可能需要几倍的交换空间量。当交换空间耗尽时,这可能会导致意外的 OOM 崩溃。
不使用交换区分配大内存对象的一种简单方法是调用 mmap()。这个调用使用起来非常简单,并且工作正常,但是有一个严重影响性能的主要问题:操作系统会定期从 mmap 区域写出脏页。
对于我的应用程序,这会将 CPU 利用率从大约 2900% 降低到大约 700%,使进程速度减慢 4 倍。
过去,RedHat 允许通过将操作系统参数 vm.flush_mapped_pages 设置为 0 来关闭此行为,但此设置不再存在,并且可能会出现意外行为:我不希望仅将操作系统参数调整为使一个进程正常工作。
FreeBSD 允许通过在 mmap 调用中使用 NO_SYNC 标志来关闭此行为,但这在 Linux 中不可用。
以下是我创建 mmap 缓冲区的方法,其中包含处理错误并删除 EINTR 的代码:
size_t n = 1048576*(size_t)1024*16; // 16G
int fd = open("mem.bin", O_TRUNC | O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
ftruncate(fd, n);
void* data = mmap(nullptr, n, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_HUGE_2MB, fd, 0);
close(fd);
unlink("mem.bin");
有没有办法让这些内存有效利用?
答案1
您可以将vm.dirty_writeback_centisecs
sysctl 设置为 0 以禁用内核的后台脏页刷新器线程。您还需要增加vm.dirty_ratio
,以便您的进程不会被迫自行执行脏写回,除非绝对必要。请注意,禁用后台刷新线程后,vm.dirty_background_ratio
、vm.dirty_background_bytes
和vm.dirty_expire_centisecs
sysctls 就无关紧要了。
不幸的是,我不认为可以在每页或每 VMA 的基础上调整写回行为。您只能针对整个 VM 子系统进行调整。