64位寻址的地址空间绝对是巨大的。我有一个程序将mmap
几个内存块,每个大小为100 - 500 MB。我将不可避免地重新映射几次,这可能会导致可用的连续空间碎片化。
无论空间发生什么碎片,对于可用的地址空间来说,肯定会非常小。
我的问题是:鉴于这些限制,在正常情况下,我可以期望所有mmap
请求成功(即由于碎片而不会失败)吗?他们失败的原因是什么?
我知道堆没有自己的整个空间,但我认为它占绝大多数。
Mac OS / Linux。
答案 0 :(得分: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
可以通过getrlimit()
查询,并且 - 在系统特定限制内 - 通过{{进行调整1}}。 setrlimit
命令使用这些命令。但是,它们返回/设置上限,即允许的总虚拟地址空间,包括进程可以创建的所有映射(通过ulimit
或mmap()
后端,malloc
)。
但总地址空间大小不同于单个映射的最大大小...
鉴于此,即使在64位Linux上,也不会耗尽虚拟地址空间;试试,试试sbrk()
相同的500GB文件,比方说,200次。 mmap最终会失败。
简而言之:
mmap()
肯定会失败。有些令人惊讶的是,在许多" 64bit"架构只是因为虚拟地址可能小于 64位有效位。确切的截止时间取决于您的CPU和操作系统,可以通过mmap()
查询或通过getrlimit(RLIMIT_AS)
设置上限。 setrlimit(RLIMIT_AS)
/ mmap()
,可以在64位上发生地址空间碎片。这最终将限制您可以映射为单个块的最大大小。预测何时会发生这种情况很难,因为它取决于你的映射历史记录"和操作系统'虚地址空间分配算法。如果ASLR(地址空间布局随机化)由操作系统完成,则可能无法详细描述,并且不能完全重现。munmap()
也会在系统(如Linux)上达到VA总限制之前失败,而过度使用会让你“问”"比系统中更多的内存(物理+交换)。malloc()
和malloc()
mmap()
和/或MAP_ANON
都会在物理+交换耗尽时失败,因为这些类型的映射需要通过实际内存或交换进行后备存储。技术更新不多:与上面提到的x86和sparc一样,新的ARMv8(64位ARM,称为" AArch64"在Linux中)MMU也有一个"分裂"地址空间/地址空间空洞 - 在地址中的64位中,只有40位是相关的。 Linux为用户提供39位,虚拟地址为MAP_PRIVATE
以上,内核为39位,虚拟地址为0 ...
,因此限制为512GB(减去应用程序尝试时已使用的内容) ... 0xFFFFFFFF.FFFFFFFF
)。
请参阅comments here(来自AArch64架构启用程序内核补丁系列)。
答案 1 :(得分:8)
mmap
和malloc
可能会失败。通常,Unix标准说的是“允许进程的地址空间”的地址范围。除此之外,
如果广告功能返回 发生错误代码 困难,你要检查 那个代码,是的,即使是检查 你的代码大小的三倍 你的打字手指会产生疼痛, 因为如果你瘦了“它不能 发生在我身上,众神肯定会 因你的傲慢而惩罚你。
(Spencer)
答案 2 :(得分:0)
只需检查man mmap中的错误列表。
答案 3 :(得分:0)
嗯,OS / C库可以自由决定是否有足够的内存。你真的没办法知道它是如何决定的(它显然是特定于操作系统的,甚至可能是可调的),但是在某些时候操作系统可能会说“不再”了。
无法分配内存的可能原因:
ulimit
设置了内存限制,则可能会更早获得ENOMEM