最大 malloc 大小低于预期

max malloc size lower than expected

本文关键字:于预期 malloc 最大      更新时间:2023-10-16

这是一个检查最大malloc大小的简单程序:

#include <iostream>
std::size_t maxDataSize = 2097152000; //2000mb
void MallocTest(void*& ptr)
{
while (1)
{
ptr = malloc(maxDataSize);
if (ptr)
{
std::cout << "Malloc success: " << maxDataSize << std::endl;
return;
}
maxDataSize -= 1024;
if (maxDataSize <= 0)
{
return;
}           
}
}
int main()
{
void* ptr = nullptr;
MallocTest(ptr);
if (ptr)
{
free(ptr);
}
system("pause");
return EXIT_SUCCESS;
}

我使用Windows 10 x64和Visual Studio 2017。当我运行该程序时,我成功获得了~1300mb的malloc调用。该程序是使用32位架构(发布模式(构建的,因此理论上内存限制等于2GB。有什么东西会导致内存碎片吗?为什么我不能分配超过 ~1300mb ?

注意:这个答案的大部分是在OP指示他们正在使用什么操作系统之前写的。这些概念仍然有效,但具体情况可能有所不同。

您说您的操作系统是 32 位的,实际上一个好的32 位实现将有 2 GB 的硬限制,因为大于PTRDIFF_MAX的对象有很多细微的问题,在使用它们时很容易导致未定义的行为,并触发处理指针算术的编译器错误。但是,您已经达到了一些较低的限制因素。

在 Linux 上,当 32 位进程在64 位内核上运行时,32 位进程的虚拟地址空间限制在大多数 arch 上为 3 GB,在某些架构上为 2 GB,某些进程的虚拟地址空间限制为 4 GB。但是,在此空间中,已经映射了许多内容,这些内容使地址空间碎片化并限制任何连续范围的长度。这包括程序本身,如果它是动态链接的,则包括动态链接器及其使用的任何共享库。

如果您的程序不是构建为 PIE(与位置无关的可执行文件(,则它在 Linux/x86 上的默认基址为 128 MB。这会拆分地址空间的前 128 MB,因为无法与连续的上部一起使用。库的加载通常略低于地址空间上限,从该端分离出一些库,但可能不会太多。ASLR(地址空间布局随机化(可能会将它们向下移动一点,但主线内核不会这样做太多,以避免对已经非常有限的地址空间进行严重碎片化。一些为额外强化而修补的内核可能会随机化更多。

最终,大型连续分配(大于半 GB 左右,甚至可能小于此(在 32 位系统上无法可靠地提供。如果需要它们,则可能需要使用64位系统。但更好的选择可能是找出不需要连续分配的备用数据结构,甚至不需要处理不适合内存的数据。