我可以在 MacBook Pro 上分配的最大内存量是多少?
What is the largest amount of memory I can allocate on my MacBook Pro?
我试图弄清楚在分配失败之前我可以分配多少内存。
这个简单的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] = ' ';
// 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;
}
当您要求内存时,操作系统保留在您实际使用它之前不实际为您提供该内存的权利。
这就是这里发生的事情:你只使用了 5 个字节。我 81 年代的 ZX1980 可以处理这个问题。
MacOS X与几乎所有现代操作系统一样,对内存使用"延迟分配"。 当您调用new
时,操作系统实际上不会分配任何内存。 它只是注意到您的程序需要一定量的内存,并且您想要的内存区域从某个地址开始。 内存仅在程序尝试使用它时才实际分配。
此外,内存以称为"页"的单位分配。 我相信 MacOS X 使用 4kb 页面,所以当你的程序写入缓冲区的末尾时,操作系统会给你 4096 字节,同时保留缓冲区的其余部分作为简单的"你的程序想要这个内存"的注释。
至于为什么达到64TB的限制,这是因为当前的x86-64处理器使用48位寻址。 这将提供 256 TB 的地址空间,该空间在操作系统和程序之间平均分配。 将 64 TB 分配加倍将完全适合程序 128 TB 的一半地址空间,只是程序已经占用了一小部分地址空间。
虚拟内存是分配比物理 RAM+交换空间更多的地址空间的关键。
malloc 使用mmap(MAP_ANONYMOUS)
系统调用从操作系统获取页面。 (假设OS X像Linux一样工作,因为它们都是POSIX操作系统)。 这些页面都是写入时复制映射到单个物理零页的。 即它们都读取为零,只有 TLB 未命中(没有页面错误,也没有分配物理 RAM)。 x86 页面是 4kiB。 (我没有提到大页面,因为它们在这里无关紧要)。
写入其中任何页面都会触发软页面错误,内核无法处理写入时复制。 内核分配物理内存的清零页,并重新连接该虚拟页以由物理页支持。 从页面错误返回时,存储将重新执行并成功。
因此,在分配 64TiB 并在其末尾存储 5 个字节后,您已经使用了额外的一页物理内存。 (并在malloc的簿记数据中添加了一个条目,但该条目可能已经分配并且位于一个肮脏的页面中。 在一个关于多个微小分配的类似问题中,malloc的簿记数据最终耗尽了所有空间)。
如果您实际上弄脏的页面多于系统的 RAM + 交换,则内核将出现问题,因为malloc
返回 NULL 为时已晚。 这称为"过度提交",某些操作系统默认启用它,而其他操作系统则不启用。 在Linux中,它是可配置的。
正如 Mark 所解释的那样,您在 64TiB 时失去了动力,因为当前的 x86-64 实现仅支持 48 位虚拟地址。 上面的 16 位必须是位 47 的副本。 (即,仅当 64 位值是低 48 位的符号扩展时,地址才是规范的)。
此要求阻止程序对高位执行任何"聪明"操作,然后在支持更大虚拟地址空间的未来硬件上中断。
- 将字符串存储在c++中的稳定内存中
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- Win32编译器选项和内存分配
- 当vector是tje全局变量时,c++中vector的内存管理
- 带内存和隔离功能的SQLite
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 迭代时从向量和内存中删除对象
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 这个指针和内存代码打印是什么?我不知道是打印垃圾还是如何打印我需要的值
- 多个文件的内存分配错误"在抛出 'std :: bad_alloc' what (): std :: bad_alloc 的实例后终止调用" [C++]
- 为什么示例代码访问IUnknown中已删除的内存
- 如何在C++类内存结构中创建"spacer"?
- 从构造函数抛出异常时如何克服内存泄漏
- malloc() 可能出现内存泄漏
- 如何理解将半精度指针转换为无符号长指针和相关的内存对齐
- 在调用FreeLibrary后,释放动态链接到具有相同版本的CRT堆的DLL的内存
- 如何针对特定情况调试和修复此双自由内存损坏问题
- 类型总是使用其大小存储在内存中吗
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存