在分配失败之前,我试图计算出可以分配多少内存。
这个简单的C++代码分配一个缓冲区(大小为1024字节),分配给缓冲区的最后五个字符,报告,然后删除缓冲区。然后,它将缓冲区的大小加倍,并重复执行,直到失败为止。
除非我遗漏了什么,否则代码能够在我的MacBook Pro上失败之前分配多达65 to的内存。这有可能吗?它怎么能分配比我在机器上更多的内存呢?我一定是错过了一些简单的东西。
int main(int argc, char *argv[])
{
long long size=1024;
long cnt=0;
while (true)
{
char *buffer = new char[size];
// Assume the alloc succeeded. We are looking for the failure after all.
// Try to write to the allocated memory, may fail
buffer[size-5] = 'T';
buffer[size-4] = 'e';
buffer[size-3] = 's';
buffer[size-2] = 't';
buffer[size-1] = '\0';
// report
if (cnt<10)
cout << "size[" << cnt << "]: " << (size/1024.) << "Kb ";
else if (cnt<20)
cout << "size[" << cnt << "]: " << (size/1024./1024.) << "Mb ";
else
cout << "size[" << cnt << "]: " << (size/1024./1024./1024.) << "Gi ";
cout << "addr: 0x" << (long)buffer << " ";
cout << "str: " << &buffer[size-5] << "\n";
// cleanup
delete [] buffer;
// double size and continue
size *= 2;
cnt++;
}
return 0;
}发布于 2016-12-30 17:40:22
当您请求内存时,操作系统保留在实际使用它之前不实际给您内存的权利。
这就是现在发生的事情:你只需要使用5个字节。我上世纪80年代的ZX81就能解决这个问题。
发布于 2016-12-30 21:34:11
与几乎所有现代操作系统一样,MacOS X使用“延迟分配”作为内存。当您调用new时,操作系统实际上不会分配任何内存。它只是简单地指出,您的程序需要一定数量的内存,而您想要的内存区域从某个地址开始。只有当程序尝试使用内存时,才会实际分配内存。
此外,内存以称为“页面”的单元分配。我相信MacOS X使用4kb的页面,所以当你的程序写到缓冲区的末尾时,操作系统会给你4096字节,而剩下的缓冲区只是一个“你的程序想要这个内存”的注释。
至于你为什么要达到64兆字节的极限,这是因为当前x86-64处理器使用48位寻址。这给出256 TB的地址空间,在操作系统和程序之间平均分配。将64 TB的分配增加一倍正好适合于您的程序的128 TB地址空间的一半,只是程序已经占用了一部分。
发布于 2016-12-31 12:00:04
虚拟存储器是分配比物理RAM+swap空间更多地址空间的关键。
malloc使用mmap(MAP_ANONYMOUS)系统调用从操作系统获取页面。(假设OS的工作方式类似于Linux,因为它们都是POSIX OSes)。这些页面都被映射到一个物理的零页上。也就是说,它们都读取为零,只有一个TLB错误(没有页面错误,也没有物理RAM分配)。一个x86页面是4kiB。(我没有提到拥抱,因为它们在这里不相关)。
对任何这些页面的写入都会触发软页错误,使内核无法处理写上的副本。内核分配物理内存的零页,并重新连接要由物理页支持的虚拟页。从页面错误返回时,存储将被重新执行并成功。
因此,在分配64 the并将5个字节存储到它的末尾之后,您已经使用了一个额外的物理内存页。(并在malloc的簿记数据中添加了一个条目,但该条目可能已经分配到了脏页中。在一个类似的关于多个微小分配的问题上,malloc的簿记数据最终耗尽了所有的空间)。
如果您实际污染的页面比系统上有RAM +交换的页面多,那么内核就会有问题,因为malloc返回NULL为时已晚。这被称为“超额承付”,一些OSes默认启用它,而另一些则不启用它。
正如Mark解释的那样,由于当前的x86-64实现只支持48位虚拟地址,所以在64TiB上就耗尽了精力。上16位需要是位47的副本。(也就是说,只有当64位值是低48位的符号扩展时,地址才是规范的)。
这一要求阻止了程序用高比特做任何“聪明”的事情,然后中断了支持更大虚拟地址空间的未来硬件。
https://stackoverflow.com/questions/41400317
复制相似问题