何时以及如何交换mmap映射的内存?

21

在我看来,将适合内存的文件进行mmap映射就像是将文件放入内存中。

假设我们有16G的RAM,并且我们首先使用mmap对一个10G的文件进行了映射。这样在访问方面应该是相当高效的。如果我们接着再对另一个10G的文件进行mmap,那会导致第一个文件被交换出去吗?或者其中的部分会被交换?如果是这样的话,这会在什么时候发生呢?是在mmap调用时还是在访问新加载的文件的内存区域时?

如果我们想要再次访问第一个文件指针所对应的内存,那么这会使它重新交换进入内存吗?也就是说,如果我们交替读取第一个文件和第二个文件相应的内存,那么是否会导致性能严重下降?

最后,如果这些都是真的,那是否更好地将多个较小的文件进行mmap映射?

2个回答

11
作为已经讨论过的内容,您的文件将被分页访问;在x86_64(和IA32)体系结构中,一页通常为4096字节。因此,在mmap时间几乎不会加载文件的任何部分。第一次访问文件中的某个页面时,内核将生成页面故障并加载您的文件的某些部分。内核可能会预取页面,因此可能会加载多个页面。它是否执行此操作取决于您的访问模式。
总的来说,如果您的工作集适合内存,则性能应该很好。也就是说,如果您只定期访问两个文件中的3G文件,只要您的进程有3G RAM可用,事情通常都会很好。
在64位系统上,没有必要拆分文件,如果您需要的部分倾向于适合RAM,那么一切都会很好。
请注意,如果您使用mmap映射现有文件,则不需要交换空间来读取该文件。当一个对象由文件系统上的文件支持时,内核可以从该文件而不是交换空间中读取。但是,如果您在调用mmap时指定了MMAP_PRIVATE,则可能需要交换空间来保存更改的页面,直到调用msync为止。

6
您的问题没有明确的答案,因为内存交换是由您的内核处理的,每个内核都有不同的实现(Linux本身根据您的用途提供不同的配置文件,如RT、桌面、服务器等)。
一般来说,无论您加载什么内容到内存中,都是使用页面完成的,因此您在内存中进行内存映射的文件是通过所有级别的内存(缓存、RAM和交换空间)之间的页面来加载(和卸载)。然后,如果您将两个10GB的数据加载到内存中,那么它们的部分将存在于RAM和您的交换空间之间,并且内核会尝试保留您现在可能使用的页面,并猜测您接下来要加载的内容。
这意味着,如果您对两个文件中的几个字节进行真正的随机访问,然后交替访问它们,您应该期望性能非常差;如果您交替顺序地访问两个文件中的连续块,您应该期望性能良好。
您可以阅读有关内核分页的虚拟内存理论的更多详细信息:

我明白了。所以重要的是页面,而不是文件。从同一文件的不同页面访问内存应该与从不同文件访问不同页面具有相同的行为/性能?那么将数据拆分成较小的文件就没有意义了吗? - Masseman
重要的是你的内核和交换策略(因为你不能控制页面工作方式)。将数据拆分成多个较小的文件需要进行计算。由于 I/O 是阻塞的,加载一个 10GB 的文件需要相当长的时间,这会导致其他服务停顿,同时你正在访问它(因为你会占用总线带宽或者因为你可能从旧的旋转驱动器中读取)。因此,将数据拆分成几个文件虽然会使加载数据变慢,但可以使系统更加响应。 - zmo
I/O 不会阻塞其他进程。也就是说,拆分文件不会提高无关操作的性能。一般来说,如果数据被 mmapped,即使在文件内部拆分,也不会改善阻塞。 - Sam Hartman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接