Tho*_*ush 25 c++ memory allocation
我试图弄清楚在分配失败之前我可以分配多少内存.
这个简单的C++代码分配一个缓冲区(大小为1024字节),分配缓冲区的最后五个字符,报告,然后删除缓冲区.然后它将缓冲区的大小加倍并重复直到它失败.
除非我遗漏了某些东西,否则代码能够在MacBook Pro出现故障之前分配高达65TB的内存.这甚至可能吗?它如何分配比我在机器上更多的内存?我一定很遗憾.
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;
}
Run Code Online (Sandbox Code Playgroud)
Bat*_*eba 44
当您要求内存时,操作系统保留在您实际使用内存之前不实际给您内存的权利.
这就是这里发生的事情:你只使用5个字节.我20世纪80年代的ZX81可以解决这个问题.
Mar*_*ark 36
与几乎所有现代操作系统一样,MacOS X对内存使用"延迟分配".当您调用时new,操作系统实际上不会分配任何内存.它只是记下你的程序需要一定量的内存,并且你想要的内存区域从某个地址开始.内存仅在程序尝试使用时实际分配.
此外,存储器以称为"页面"的单位分配.我相信MacOS X使用4kb页面,所以当你的程序写入缓冲区末尾时,操作系统会给你4096个字节,同时保留缓冲区的其余部分就像"你的程序需要这个内存"一样.
至于为什么你达到64TB的限制,这是因为当前的x86-64处理器使用48位寻址.这提供了256 TB的地址空间,可在操作系统和程序之间平均分配.将64 TB分配加倍将完全适合您程序的128 TB地址空间的一半,除了程序已经占用了一点点.
虚拟内存是分配比物理RAM +交换空间更多地址空间的关键.
malloc使用mmap(MAP_ANONYMOUS)系统调用从OS获取页面.(假设OS X的工作方式与Linux类似,因为它们都是POSIX操作系统).这些页面都是写入时复制映射到单个物理零页面.即,只有TLB未命中(没有页面错误且没有物理RAM分配),它们都读为零.一个86页4kiB.(我没有提到大页面,因为它们在这里不相关).
写入任何这些页面会触发内核的软页面错误,以处理写入时复制.内核分配物理内存的归零页面,并重新连接该物理页面支持的虚拟页面.从页面错误返回时,存储重新执行并且此次成功.
因此,在分配64TiB并将5个字节存储到它的末尾之后,您已经使用了一个额外的物理内存页面.(并且在malloc的簿记数据中添加了一个条目,但这可能已经分配并且在一个脏页面中.在一个类似的关于多个微小分配的问题中,malloc的簿记数据最终耗尽了所有空间).
如果你实际上弄脏了比系统有RAM + swap更多的页面,内核就会出现问题,因为malloc返回NULL 已经太晚了.这称为"过度使用",某些操作系统默认启用它,而其他操作系统则不支持.在Linux中,它是可配置的.
正如Mark解释的那样,你在64TiB上失去了动力,因为当前的x86-64实现只支持48位虚拟地址.高16位需要是位47的副本.(即,如果64位值是低48位的符号扩展,则地址仅是规范的).
这个要求阻止程序用高位做任何"聪明"的事情,然后打破未来支持更大虚拟地址空间的硬件.
| 归档时间: |
|
| 查看次数: |
2116 次 |
| 最近记录: |