在64位进程中,我的mmap/malloc请求是否会被拒绝?

Joe*_*Joe 13 c malloc operating-system memory-management mmap

64位寻址的地址空间绝对是巨大的.我有一个程序,将有mmap几个内存块,每个大小为100 - 500 MB.我将不可避免地重新映射几次,这可能会导致可用的连续空间出现碎片.

无论空间出现什么碎片,对于可用的地址空间来说肯定会很小.

我的问题是:鉴于这些限制,在正常情况下,我可以期望所有mmap请求成功(即由于碎片而不会失败)吗?他们失败的原因是什么?

我知道堆本身没有整个空间,但我认为它占绝大多数.

Mac OS/Linux.

Fra*_*kH. 27

请注意,"64位操作系统"的地址空间大小不一定涵盖整个64位范围.

例如,在x64(64位x86,又名"AMD64")上,实际可用的虚拟地址范围是"仅"2x128TB,即两个不相交的47位块中的48位.在某些SPARC系统上,它是2x2TB或2x8TB(41/44位).这是由于MMU在这些平台上的工作方式.

除了这些架构限制之外,操作系统布局地址空间的方式也起到了重要作用.
例如,x64上的64位Windows将(甚至64位)应用程序的虚拟地址大小限制为8TB(每个内核和用户端1).

在UN*X系统(包括Linux,MacOSX和*BSD)上,RLIMIT_AS可以查询via getrlimit(),并且 - 在系统特定的限制内 - 调整via setrlimit.该ulimit命令使用这些.但是,它们返回/设置上限,即允许的总虚拟地址空间,包括进程可以创建的所有映射(通过mmap()malloc后端sbrk()).但总地址空间大小不同于单个映射的最大大小...

鉴于此,即使在64位Linux上,也不会耗尽虚拟地址空间; 试试,测试mmap()相同的500GB文件,比方说,200次.mmap最终会失败.

简而言之:

  • mmap()一旦你离开虚拟地址空间,肯定会失败.有些令人惊讶的是,这在许多"64位"架构上是可行的,因为虚拟地址可能少于 64位有效位.确切的截止时间取决于您的CPU和操作系统,并且可以通过getrlimit(RLIMIT_AS)或设置通过查询上限setrlimit(RLIMIT_AS).
  • 通过频繁使用mmap()/ munmap()以不同的顺序和不同大小的块,可以在64位上发生地址空间碎片.这最终将限制您可以映射为单个块的最大大小.预测何时会发生这种情况很难,因为它取决于您的"映射历史"和操作系统的虚拟地址空间分配算法.如果ASLR(地址空间布局随机化)由OS完成,则它可能是不可预测的,并且不完全可重现.
  • malloc() 也会在系统(如Linux)上达到总VA限制时失败,其中过度使用允许您"询问"比系统中更多的内存(物理+交换).
  • 在设备/操作系统在没有过量使用已启用,都malloc()mmap()MAP_ANON和/或MAP_PRIVATE在物理+交换被耗尽,因为这些类型的映射需要通过实际的内存或交换后备存储将失败.

小技术更新:像x86和SPARC上面提到的,新的ARMv8(64位ARM,被称为"AArch64"在Linux中)MMU也有一个"分裂"的地址空间/地址空间洞-在地址从64位中,只有40是相关的.Linux为用户提供39位0 ...,向前提供虚拟地址... 0xFFFFFFFF.FFFFFFFF,为内核提供39位,虚拟地址,因此限制为512GB(减去应用程序尝试时已使用的内容mmap).
请参阅此处的注释(来自AArch64架构启用程序内核补丁系列).

  • +1你的代表应该超过815这样的好答案. (2认同)

Fre*_*Foo 8

mmap并且malloc可能由于缺少物理内存(RAM +交换)而失败.通常,Unix标准说的是"允许进程的地址空间"的地址范围.除此之外,

如果一个函数被广告以便在遇到困难时返回错误代码,那么你应该检查那个代码,是的,即使检查代码的大小增加了三倍并且在你的打字手指上产生疼痛,如果你把它弄得"瘦"的话.不可能发生在我身上,众神肯定会因你的傲慢而惩罚你.

(斯宾塞)