我可以在MacBook Pro上分配的最大内存量是多少?

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可以解决这个问题.

  • 那么,操作系统比你想象的更聪明.你认为macbook pro不是很好看吗? (27认同)
  • 对.一个精心设计的操作系统将以块为单位为您提供内存; 通常称为*pages*. (7认同)
  • 谷歌://存储器+过量使用 (5认同)
  • 哦.所以,如果我写入每个缓冲区中的每个字符,它会更早失败?这就是你说的吗? (3认同)

Mar*_*ark 36

与几乎所有现代操作系统一样,MacOS X对内存使用"延迟分配".当您调用时new,操作系统实际上不会分配任何内存.它只是记下你的程序需要一定量的内存,并且你想要的内存区域从某个地址开始.内存仅在程序尝试使用时实际分配.

此外,存储器以称为"页面"的单位分配.我相信MacOS X使用4kb页面,所以当你的程序写入缓冲区末尾时,操作系统会给你4096个字节,同时保留缓冲区的其余部分就像"你的程序需要这个内存"一样.

至于为什么你达到64TB的限制,这是因为当前的x86-64处理器使用48位寻址.这提供了256 TB的地址空间,可在操作系统和程序之间平均分配.将64 TB分配加倍将完全适合您程序的128 TB地址空间的一半,除了程序已经占用了一点点.

  • @tbodt - 他们没有.基本上,它理论上是*64位地址空间,但出于布局原因,高16位是无线的,因为芯片无论如何都无法在物理上支持那么多内存.这使得硅设计更容易,因为你没有到处都是这些巨大的总线部分,但实际上并没有做任何事情. (8认同)
  • 请注意,Windows也会进行延迟分配*,但它不会过度使用*,因此在Windows上,您应该无法分配超过总RAM +交换空间 - 已经在使用的内存. (8认同)
  • 他们使用额外的16位地址? (2认同)

Pet*_*des 7

虚拟内存是分配比物理RAM +交换空间更多地址空间的关键.

malloc使用mmap(MAP_ANONYMOUS)系统调用从OS获取页面.(假设OS X的工作方式与Linux类似,因为它们都是POSIX操作系统).这些页面都是写入时复制映射到单个物理零页面.即,只有TLB未命中(没有页面错误且没有物理RAM分配),它们都读为零.一个页4kiB.(我没有提到大页面,因为它们在这里不相关).

写入任何这些页面会触发内核的软页面错误,以处理写入时复制.内核分配物理内存的归零页面,并重新连接该物理页面支持的虚拟页面.从页面错误返回时,存储重新执行并且此次成功.

因此,在分配64TiB并将5个字节存储到它的末尾之后,您已经使用了一个额外的物理内存页面.(并且在malloc的簿记数据中添加了一个条目,但这可能已经分配并且在一个脏页面中.在一个类似的关于多个微小分配的问题中,malloc的簿记数据最终耗尽了所有空间).

如果你实际上弄脏了比系统有RAM + swap更多的页面,内核就会出现问题,因为malloc返回NULL 已经太晚了.这称为"过度使用",某些操作系统默认启用它,而其他操作系统则不支持.在Linux中,它是可配置的.


正如Mark解释的那样,你在64TiB上失去了动力,因为当前的x86-64实现只支持48位虚拟地址.高16位需要是位47的副本.(即,如果64位值是低48位的符号扩展,则地址仅是规范的).

这个要求阻止程序用高位做任何"聪明"的事情,然后打破未来支持更大虚拟地址空间的硬件.