为什么 2^80 字节的内存分配不会失败?
Why memory allocation of 2^80 bytes doesn't fail?
以下代码不会引发异常并打印"成功"。为什么?
#include <iostream>
int main()
{
size_t size = size_t(1024)*1024*1024*1024*1024*1024*1024*1024;
char* data = new char[size];
if (data == NULL)
std::cout << "fail" << std::endl;
else
std::cout << "success" << std::endl;
return 0;
}
- 编译器: g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
- 操作系统: 乌班图 12.04
- 内存: 8 GB
如果这就是它的工作原理,我该如何检查我是否有足够的内存?
[编辑:使我的愚蠢代码更正确一点,现在如果我删除两个*1024
,它至少会在x64上失败]
我的编译器可以回答这个问题:
$ g++ --version
g++ (GCC) 4.7.1 20120721 (prerelease)
Copyright (C) 2012 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ -Wall -Wextra -pedantic q12507456.c++
q12507456.c++: In function 'int main()':
q12507456.c++:5:42: warning: integer overflow in expression [-Woverflow]
$
这很可能是您请求的数字太大而无法存储在整数中,并且您在这里遇到溢出,并且分配的内存实际上远远少于您想象的。
这里 2^80 = 根据 http://en.wikipedia.org/wiki/Yobibyte 1208925819614629174706176
1024*1024*1024*1024*1024*1024*1024*1024
计算时会导致整数溢出 - 也就是说,它将取模 2^32(或 2^64,取决于您的系统),这是可以分配的零字节。
请注意,在 Linux 上,malloc
(最终支持 new
)可能会过度提交:
从 2.1.27 开始,有一个 sysctl
VM_OVERCOMMIT_MEMORY
和 proc 文件 /proc/sys/vm/overcommit_memory,值为 1:执行过度提交,0 (默认值):不要。
malloc
将成功并保留 VA,但不使用页面备份它。当访问页面时,它可能会也可能不会成功提交它。OOM 杀手可能会运行。如果全部失败,您将在访问时获得 GPF。
无论这种行为是疯狂的(理智的人在这个阵营)还是聪明的(疯狂的人在这个阵营),意见分歧。
也许您知道以下内容,但为了澄清起见,我将说明这一点。一个异常不是从字面上抛出的,代码是由 if 语句测试的。无论您在测试中使用什么术语和方法,都有一个更相关的观察结果需要注意。 您的系统保留整数的最大值,C++将在编译期间通过执行检查并相应地采取某种行为来考虑它。再一次,您可能也已经知道这一点。 我的猜测是,该值要么回到 0,然后达到过多的数量,要么在指针开始指向它之前存在的值保持不变(最有可能)。在这种情况下,指针将不会NULL
。尝试在声明时给出使其NULL
,然后分配内存并查看天气是否通过您的 if 语句。
- 当需要超过16GB的连续内存时,内存分配失败
- 分配给转换运算符失败-C++
- 在构造函数中分配内存失败是如何冒泡的
- 用户DLL/EXE中的堆分配失败
- 如何防止连续使用"new"时分配失败时内存泄漏
- 分配失败了文件*类
- C++内存分配失败(使用 new & delete)
- 如何创建随机内存分配失败
- 如果我的C++“新”内存分配失败,如何找出返回值
- 在现代 64 位系统上,可能导致内存分配失败的原因
- 构造函数 - 内存分配失败
- set_new_handler (std::new_handler func) 失败后的构造函数调用,用于内存分配失败
- 指针的内存分配失败
- 使用新运算符和2D数组防止内存分配失败的正确方法
- 使用new时内存分配失败
- 无法捕获内存分配失败
- 测试内存分配失败时的正确行为
- 如何使用new操作符检查内存分配失败
- 处理内存分配失败
- 捆绑检查分配失败并返回错误的整洁方式