![mmap 是否允许创建比物理内存量大得多的映射?](https://linux22.com/image/209152/mmap%20%E6%98%AF%E5%90%A6%E5%85%81%E8%AE%B8%E5%88%9B%E5%BB%BA%E6%AF%94%E7%89%A9%E7%90%86%E5%86%85%E5%AD%98%E9%87%8F%E5%A4%A7%E5%BE%97%E5%A4%9A%E7%9A%84%E6%98%A0%E5%B0%84%EF%BC%9F.png)
显然,mmap
受到最大可用虚拟地址空间块的大小的限制。但假设我们有一个 64 位系统,对于大多数用途来说这几乎是无限的。我们还假设没有配置交换分区。
在匿名映射的情况下,大小必须限制为可用物理内存的总量。
但是,在文件支持的映射的情况下,我想知道是否存在基于物理内存量的限制,例如映射的大小最多可以是物理内存量的X倍?或者mmap
只要不达到虚拟地址空间限制,就允许我将任意大的文件映射为单个块?例如,如果我有 32 GiB 的 RAM,我可以成功创建mmap
1 TiB 的磁盘文件吗?
特别询问有关 Linux 的问题,以防万一。 (我尝试使用 64 GiB 文件,它似乎可以工作。不幸的是,我没有比这更多的可用磁盘空间。)
答案1
使用mmap()
映射文件不会将文件复制到物理内存,因此没有理由限制它。只要整个文件能够用虚拟地址空间来表示,就可以进行映射。其工作原理是每个页面并不驻留在内存中,因此访问它会触发页面错误。内核透明地利用这个机会访问文件的该部分。这允许用户进程操作一个非常大的文件,而不需要做一堆效率低下 read()
,write()
, 和seek()
循环(尽管它仍然会导致上下文切换,如某物必须实际处理 VFS)。
请注意,匿名映射能超过剩余物理内存,如果内存过量使用已启用,因为页表已设置,以便每个虚拟页指着物理的零页。任何读取都会返回零,但是写入会导致页面错误,内核需要找到一个空闲的物理页来存储数据,此时它可以更新页表。当然,这需要你有足够的物理内存+交换空间。过度使用是一种有用的优化,因为大多数内存分配器都会积极地为其堆请求内存,即使其中大部分未使用。
您甚至可以映射文件大于地址空间,但不是一次调用就能一次性全部完成mmap()
。
作为附录,即使在 64 位系统上,您也可能无法使用完整的 64 位地址空间:
$ grep -m1 "address sizes" /proc/cpuinfo
address sizes : 39 bits physical, 48 bits virtual
在该系统上,由于 48 位虚拟地址空间被分成两部分,因此您可以映射一个大小为 2 47 的文件字节或 128 TiB 的文件(实际上要小一些,因为一些地址空间已被使用)。