【问题标题】:Any way to reserve but not commit memory in linux?有什么方法可以在linux中保留但不提交内存?
【发布时间】:2025-12-08 12:25:02
【问题描述】:

Windows 有 VirtualAlloc,它允许您保留一个连续的地址空间区域,但实际上并不使用任何物理内存。稍后当您想要使用它(或其中的一部分)时,您再次调用 VirtualAlloc 以提交先前保留页面的区域。

这实际上非常有用,但我想最终将我的应用程序移植到 linux - 所以如果以后不能移植它,我不想使用它。 linux有没有办法做到这一点?

编辑 - 用例

我正在考虑分配 4 GB 或类似的虚拟地址空间,但一次只提交 64K。这将为我提供一种零拷贝方式来将数组增加到 4 GB。这一点很重要,因为典型的双倍数组大小和副本会为非常大的数组引入看似随机的不可接受的延迟。

【问题讨论】:

  • 这对您有什么用例?为什么区分询问是否可以分配空间(保留它)和实际使用内存中的空间之间的区别很重要?
  • 看起来常规的 alloc 应该可以正常工作。如果内存没有被使用,它会被换出,当你开始使用它时,它会被带回内存
  • @xyld:一个从虚拟地址空间中扣除块,另一个从虚拟内存(页面文件)中扣除。
  • 顺便说一句,无需复制即可解决此问题的一种快速方法是 mremap(尽管它只是开始在大缓冲区大小 (>65K) 下胜过 TLB 无效和其他成本)
  • 保留但不提交内存对于减少“随机不可接受的延迟”可能没有您想象的那么大。它可能会创建它。您将在未来的某个时候引入页面错误,并且为这些错误提供服务会产生更多的延迟,这就是 RTOS 通常避开这种情况的原因。

标签: linux memory-management virtualalloc


【解决方案1】:

mmap 一个特殊文件,比如/dev/zero(或使用MAP_ANONYMOUS)作为PROT_NONE,稍后使用mprotect 提交。

【讨论】:

  • 是的。当您正常分配一块任意大小的内存时,C 库/内核实际上隐式地执行此操作。页面是保留的,但在您触摸它们之前不会实际映射。映射 /dev/zero(使用 MAP_PRIVATE)只是一种特殊的 malloc。
  • @MarkR:对于 linux 来说确实如此,对于 vm overcommit sysctl 的某些设置。 /dev/zero 方法的 mmap 应该适用于任何 POSIX 操作系统,包括禁用 vm overcommit 的 linux。阅读 vm overcommit 文档,/dev/zero 和无写访问权限的组合是导致块不计入提交限制的原因。
【解决方案2】:

您可以使用内核过量使用在系统范围内启用此功能。这通常是许多发行版的默认设置。

这里是解释http://www.mjmwired.net/kernel/Documentation/vm/overcommit-accounting

【讨论】:

  • 哦,那太酷了……虽然不能只为一个进程打开它,对吧?
  • @dlamotte:它通常在桌面系统上默认打开。实时系统会不赞成这种行为(以及一般的按需分页),但它在桌面上是有益的,我还没有遇到过没有打开它的。只要您从不写入您分配的内存(通过几乎任何方式),内核只会保留它。
【解决方案3】:

VirtualAlloc() 的 Linux 等效项是 mmap(),它提供相同的行为。然而,正如评论者指出的那样,只要内存未初始化(例如通过calloc() 或用户代码),保留连续内存就是调用malloc() 的行为。

【讨论】:

  • 你说得对,我惊讶地发现它是在你链接的 malloc 的文档中指定的。
  • 顺便说一句,只有 malloc 我能够在 linux x64 机器上分配 128TB 的虚拟地址空间,以 4GB 块(2^15-3 左右)约 500MB开销(实际上太低了,以至于每个 4kb 页面都没有页表条目,但对于每个 2MB 页面的 8 字节条目来说正好合适(内核中支持透明大页面?)
【解决方案4】:

"看似随机的不可接受的延迟 对于非常大的数组

您还可以考虑使用 mlock() 或 mmap() + MAP_LOCKED 来减轻分页的影响。许多 CPU 支持超大(又名大)页面,即大于 4kb 的页面。这些较大的页面可以减轻 TLB 对流式读/写的影响。

【讨论】:

  • 问题仍然是副本,即使没有分页,复制 2GB 数组来制作 4GB 数组也太慢了。如果您可以避免移动内存,则添加第 20 亿个和第 1 个元素时不会出现延迟。
最近更新 更多