malloc的1TB内存不会失败?

时间:2017-05-15 14:58:32

标签: c malloc

//gcc 5.4.0

#include  <stdio.h>

int main(void)
{
    // Try to reserve 1 TB of memory
    int *arr = malloc(1024 * 1024 * 1024 * 1024);
    // Unfortunately most systems will actually allow this (swapping etc.)
    if (arr == NULL) {
        printf("Was not able to reserve memory!\n");
    }
    printf("Everything is ok\n");

    return 0;
}

编译器选项:-Wall -std=c99 -o a.out source_file.c

输出(&#34;一切都好,#34;)让我感到困惑。我显然没有1TB的内存 - 根据C-Reference,malloc应该返回NULL,并且只有当(!)出现问题时才会返回。

这显然不会发生在这里。有人可以解释一下吗?

5 个答案:

答案 0 :(得分:2)

  

1024 * 1024 * 1024 * 1024

这些是int类型的整数常量。当相乘时,操作将在int类型上执行。结果将是int类型。

int很可能无法在系统上保存大于2 ^ 32/2 -1 = 2.14*10^9的值。

意味着溢出signed int并调用未定义的行为。任何事情都可能发生,包括malloc分配一些随机数据块。

答案 1 :(得分:2)

  

根据C-Reference,malloc应该返回NULL,并且只有当(!)出现问题时才会返回。

这是不正确的。

malloc()在两个条件下返回NULL

  1. 如果无法分配内存,则空指针

  2. 在分配0时,如果malloc()返回NULL或非NULL指针(无法取消引用),则执行定义。

  3. OP的1024 * 1024 * 1024 * 1024溢出32位int数学,这是未定义的行为或UB。 @WhozCraig hint。典型的结果是截断的乘积为0. OP的系统然后返回非NULL指针,用于零字节分配,因为&#34;不能保留记忆!\ n&#34;没打印。

    如果OP的平台使用罕见的64位int,则内存的真实分配可能是deferred

    OP还错过了编译器的有用建议。增加警告选项。以下某些内容将报告警告。

    // -pedantic -Wall -Wextra -std=c99  -o a.out source_file.c
    
    int *arr = malloc(1024 * 1024 * 1024 * 1024);
    // warning: integer overflow in expression [-Woverflow]
    

    确保表达式的数学类型符合/超过目标类型。 @Olafreasons not to use 100 * 1000 * 1000

    int *arr = malloc((size_t) 1024 * 1024 * 1024 * 1024);
    

答案 2 :(得分:0)

来自malloc(3)联机帮助页:

  

默认情况下,Linux遵循乐观的内存分配策略。这意味着当malloc()返回非NULL时,无法保证内存确实可用。

当然,这假设你在Linux上。

答案 3 :(得分:-1)

您没有1TB物理内存,但大多数操作系统都支持虚拟内存,并以磁盘空间为后盾。 当malloc请求内存时,系统会分配虚拟内存。它的一部分将是真正的内存,其余部分很可能是你的高清文件。

答案 4 :(得分:-2)

1024 * 1024 * 1024 * 1024最有可能调用未定义的行为: 1024int常量。使用&#34;最大的&#34;完成操作。两个操作数的类型,但至少int。两个操作数均为int,因此乘法类型为int * int -> int。以下乘法相同。即最终结果是int。在典型系统上int不超过32位。 参数的类型与表达式无关。

乘法的结果溢出int(除非它超过41位),这会调用未定义的行为。任何事情都可能发生(通常但不保证:结果被截断,产生0)。

为避免这种情况,您应该使用(size_t)1024 * 1024 * 1024 *1024。这将(根据转换规则)将使用您系统上的size_t标准类型执行计算。

事先使用静态断言来确保size_t可以表示结果:

_Static_assert(SIZE_MAX >= 1024ULL * 1024 * 1024 *1024, "size_t is too small");`

如果没有这个,乘法会在一个太小的size_t上被截断(对于有符号和无符号整数,规则是不同的!)并且最终传递0

根据标准malloc(0) is implementation defined either NULL or a pointer which must not be used to access an object

记住所有这些,您的代码可能会返回一个非空指针,该指针不能用于访问。但是当你测试它时,它很好,但没用。