mmap:映射文件会立即加载到内存中吗?

问题描述 投票:11回答:4

从手册中,我只知道mmap()将文件映射到虚拟地址空间,因此可以随机访问该文件。但是,我不清楚映射的文件是否立即加载到内存中?我猜想内核会按页面管理映射的内存,并且按需加载它们,如果我仅执行一些读取和写入操作,则只会加载几个页面。正确吗?

linux mmap
4个回答
23
投票

不,是的,也许。这取决于。

调用mmap 通常”仅意味着对于您的应用程序,映射文件的内容被映射到其地址空间好像文件被加载到那里。或者,就好像文件确实存在于内存中一样,就好像它们是一个文件一样(包括将更改写回到磁盘上,假设您具有写访问权限)。

不多也不少。它没有加载任何东西的概念,应用程序也不知道这意味着什么。

尽管虚拟内存系统使应用程序看起来像这样,但是应用程序并不真正了解诸如内存之类的任何东西。应用程序可以“查看”(和访问)的内存可能与实际的物理内存相对应,或者原则上可以随时更改,而无需事先警告,也没有明显的理由(对您的应用程序来说很明显)。除了可能由于页面错误而导致一小段延迟之外,应用程序(原则上)完全不知道任何此类事件的发生,并且对其几乎没有或没有控制权1

通常,由于遇到故障,应用程序将根据需要从映射文件(包括主可执行文件!)中加载页面。但是,操作系统通常会尝试推测性地预取数据以优化性能。

实际上,调用mmap将立即begin从映射的开始(异步地)预取页面,直至达到特定的实现指定大小。原则上,这意味着对于小文件,答案为“是”,对于大文件,答案为“否”。但是,mmap不会阻止等待预读完成,这意味着您无法保证mmap返回后立即有任何文件在RAM中(无论如何,您始终无法保证!) 。就此而言,答案是“也许”。

在Linux下,我上次查看时,默认的预取大小为31个块(〜127k)-但这可能已更改,并且它是一个可调参数。当触摸预取区域附近或末尾的页面时,更多的页面将被异步预取。如果您已经提示MADV_RANDOMmadvise,则预取“不太可能发生”,在Linux下,这将完全禁用预取。

另一方面,提供MADV_SEQUENTIAL提示将从映射开始就异步“更积极地”预取(并且可能会更快地丢弃访问的页面)。在Linux下,“更积极”表示两倍于正常数量。

给出MADV_WILLNEED提示表明(但不保证)尽快加载给定范围内的所有页面(因为您要访问它们)。操作系统可能会忽略这一点,但是在Linux下,它被视为命令而不是提示,直到进程的最大RSS限制和实现指定的限制(如果我没记错的话,是物理RAM数量的1/2) )。注意,MADV_DONTNEED可能在Linux下错误实现。提示不是按照POSIX指定的方式进行解释的,即您可以暂时将页面分页出来,而是您要丢弃它们。对于只读映射的页面,这没有什么大的区别(除了很小的延迟,您说可以的),但是对于其他所有内容,它肯定是[[does事宜。特别是,使用MADV_DONTNEED认为Linux将在操作系统懒惰地将它们写入磁盘后[[不是工作原理释放不需要的页面!您必须明确同步,否则请准备一个惊喜。

在调用readahead之前已在文件描述符上调用了mmap(或者,以前已经读取/写入了文件),文件的内容实际上将实际上立即在RAM中。但是,这仅是实现细节(统一的虚拟内存系统),并且受系统内存压力的影响。

调用mlock将-假设成功2-立即将请求的页面加载到RAM中。它会阻塞,直到实际显示所有页面为止,并且您可以保证页面将保留在RAM中,直到您将它们解锁为止。

1

存在用于查询(mincore)当前是否确实存在特定范围内的任何页面或所有页面的功能,并且可以向操作系统提示有关您[[想要]]的内容的功能。看到没有任何硬保证(madvise)发生的情况,最后是强制为特权进程强制将有限的页面子集显示在内存(mlock)中的功能。
2
可能不是因为缺少特权,也不是因为存在配额或物理RAM数量过多。

2
投票

是。 mmap的整个

point
可以比仅将所有内容存储到内存中更有效地管理内存。
当然,任何给定的实现在某些情况下可能会决定一次读取整个文件更为有效,但这对于调用mmap的程序应该是透明的。

默认情况下,mmap()仅配置映射并返回(快速)。


1
投票

1
投票
© www.soinside.com 2019 - 2024. All rights reserved.