我面临着有关映射 RAM 文件的设计问题。 RAM 内文件长约 400MB,最坏情况下约为 100k 页(除非内核选择使用每个 2MB 的透明大页,在这种情况下它将降至 200)。
我不知道是否保持 mmap 打开,或者是否先
mmap
它,然后munmap
它,当我稍后需要它时再次mmap
它。该文件将被大量使用,就像它可以在几分钟内使用多次,然后几个小时内不再使用。
我并不真正担心性能,但我很好奇以毫秒为间隔对一个由数千个页面组成的大部分进行 mmaping 和 mumapping 的性能成本是多少。内核必须做哪些工作来进行映射、设置每个页面的权限等?
这很大程度上取决于您的程序运行的具体环境。
理论上,内核是智能的,并维护一个称为“页面缓存”的缓存,其中最近映射的页面在从用户空间程序取消映射后可以在技术上无限期地不受干扰。它们仍然使内存保持忙碌状态,但可以随时丢弃并在需要内存时写回磁盘。如果您打开
htop
或类似工具,您可以看到有多少内存用于缓存:
free
命令还以文本形式显示此信息:
$ free -h
total used free shared buff/cache available
Mem: 31Gi 5.4Gi 22Gi 164Mi 4.0Gi 25Gi
Swap: 31Gi 0B 31Gi
当您映射文件时,除非明确请求,否则通常不会立即将其读入内存,而是在访问每个页面时按需读入内存。对新映射的第一次访问会生成页面错误,然后内核才将实际数据加载到内存中。完成此操作后,页面也会缓存在页面缓存中。
因此,如果您编写一个程序来映射一个大文件,使用它,取消映射,然后再次重新映射它以在短时间内重新使用它,那么第二次页面肯定已经在页面缓存。在这种情况下,内核需要做的唯一工作就是填充相应的页表条目,这很快。
但是,取消映射和重新映射之间经过的时间越长,页面从页面缓存中逐出并写入磁盘的可能性就越大。这是因为几乎所有文件支持的映射都使用页面缓存,而内存 (RAM) 通常是有限的。与您的程序一起运行的程序也会不断请求新内存,内核可能必须通过丢弃页面缓存中的页面来取回其中一些内存。
归根结底,您所描述的操作(不断取消映射和重新映射)是快还是慢实际上取决于您有多少可用内存以及系统当前的繁忙程度。不过,绝对快的是始终保持文件映射,并可能将其锁定在 RAM (
mlock(2)
) 中,这样它就不会被换出。当然,是否可以这样做取决于具体情况,但纯粹从性能角度来看,这将是最佳选择。
sysctl
旋钮进行更改,特别是:
/proc/sys/vm/dirty_background_bytes
/proc/sys/vm/dirty_background_ratio
/proc/sys/vm/dirty_bytes
/proc/sys/vm/dirty_expire_centisecs
/proc/sys/vm/dirty_ratio
请参阅此文档页面,其中描述了它们以获取更多信息。