【问题标题】:Why memory allocation of 2^80 bytes doesn't fail?为什么 2^80 字节的内存分配不会失败?
【发布时间】:2012-09-20 06:59:06
【问题描述】:

以下代码不会引发异常并打印“成功”。为什么?

#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
  • 操作系统:Ubuntu 12.04
  • 内存:8 GB

如果这就是它的工作方式,我如何检查我是否有足够的内存?

[编辑: 让我的愚蠢代码更正确一些,现在如果我删除两个 *1024]

,它至少会在 x64 上失败

【问题讨论】:

  • 提示:整数溢出
  • 无论如何,这个程序永远不会打印"fail",因为new在失败时不会返回空指针。它会抛出 std::bad_alloc
  • @valdo 这个程序不会覆盖任何东西。
  • 不得不说,虽然我的第一反应是一脸懵逼,但这个问题还是把我逗笑了。它显示了研究努力的事实意味着我会支持它。标题本身就是点击诱饵的一个很好的例子。
  • @Mysticial:自从我阅读了您的第 1 条评论后,我已经做了大约 2^80 次面部护理,并且笑得很开心。我想,这是我作为 C++ 开发人员的第 14 天这一事实可以给我一些借口。

标签: c++ memory-management


【解决方案1】:

我的编译器可以回答这个问题:

$ 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】:

    这很可能是因为您请求的数字太大而无法存储在整数中,并且您在此处遇到溢出,并且分配的内存实际上远比您想象的要少。

    这里 2^80 = 1208925819614629174706176 根据http://en.wikipedia.org/wiki/Yobibyte

    【讨论】:

    • the memory allocated is in fact far far less than you think it is - 仅供参考,我的编译器设置size == 0
    【解决方案3】:
    1024*1024*1024*1024*1024*1024*1024*1024
    

    在计算时会导致整数溢出 - 也就是说,它将取模 2^32(或 2^64,具体取决于您的系统),这是可以分配的零字节。

    【讨论】:

    • “小得多的金额”为零。
    【解决方案4】:

    请注意,在 linux 上malloc(最终支持new)可以overcommit

    从 2.1.27 开始有一个 sysctl VM_OVERCOMMIT_MEMORY 和 proc 文件 /proc/sys/vm/overcommit_memory 值为 1:执行过度使用,0 (默认):不要。

    malloc 将成功并保留 VA,但不会使用页面备份它。当一个页面被访问时,它可能会也可能不会成功提交它。 OOM Killer 可以运行。如果一切都失败了,您将获得一个 GPF 访问权限。

    对于这种行为是疯狂的(理智的人属于这个阵营)还是聪明的(疯狂的人属于那个阵营),意见存在分歧。

    【讨论】:

    • how do I check that I have enough memory? -> 不是通过分配,因为过度使用问题。
    • 我仍然会摆脱“因为...” - 失败的原因不是过度使用,而是整数溢出。
    • @themel:很公平。在我的 g++(在 x86 上运行的 4.1.2)上,它不会使用原始代码编译:error: overflow in constant expression.
    • OOM 杀手是 batsh_t insane,但在正常情况下通常不会导致问题。不幸的是,由于 Linux 在很长一段时间内默认情况下都会过度使用,因此无法安全地禁用它,因为许多程序不是为处理 malloc() 故障而编写的(我在看着你,Apache httpd)。有关此主题的更多讨论,请访问here
    • @Justin:是的,这个类比很棒:)
    【解决方案5】:

    也许您知道以下内容,但我将说明它只是为了澄清。不是字面上抛出异常,而是通过 if 语句测试代码。无论您在测试中使用什么术语和方法,都需要注意更相关的观察结果。 您的系统拥有整数的最大值,C++ 将在编译期间通过检查并采取相应的方式将其考虑在内。再一次,你可能也已经知道了。 我的猜测是该值要么回到 0,然后达到过量,要么在指针开始指向它之前存在的值保持不变(很可能)。在这种情况下,指针不会是NULL。尝试在声明时将其设为NULL,然后分配内存并查看天气是否通过您的 if 语句。

    【讨论】:

    • “一个异常并没有真正被抛出”——这是正确的术语。您期望出现std::bad_alloc 异常。结果实际上没有由 if 语句测试。
    • 仅供参考,我的编译器已将溢出值设置为 0。
    猜你喜欢
    • 2012-05-09
    • 2014-05-31
    • 1970-01-01
    • 1970-01-01
    • 2017-09-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-02
    相关资源
    最近更新 更多