尽管有足够的可用内存(32 GB),但在malloc()分配12 GB内存后仍收到“分段错误:11”

时间:2019-07-01 19:49:39

标签: c memory

我有一个程序,需要分配2个15亿长度的整数数组。这是一个编码挑战(https://projecteuler.net/problem=282),没有办法使用这么大的数组(如果有,请不要告诉我;我应该自己找到答案)。它们必须是32位整数,因为它们的值在0到15亿之间。 30亿个整数占用了大约12 GB的空间,因此我决定使用具有32 GB内存的EC2 r5.xlarge实例,但是在我的C代码中遇到了segmentation fault错误。当我在本地测试代码时,它适用于较小的数组,但在完整版本上收到segmentation fault:11错误。

我已经上网了,尝试用ulimitulimit -m 15000000更改ulimit -v 15000000中的设置(两个数字均以KB为单位)。这些已经设置为unlimited,所以我认为这没有任何作用。

C代码

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main(int argc, char* argv[]) {
    int magic = pow(14, 8); // 14**8 is 1,475,789,056
    // more lines
    int* a = malloc(4 * magic);
    int* b = malloc(4 * magic);
    if (a == NULL || b == NULL) {
    printf("malloc failed\n");
    exit(0);
    }
    for (int i = 0; i < magic; i++) a[i] = (2 * i + 3) % magic;
    // some more lines

我在EC2实例上的C代码中遇到segmentation fault错误。当我在本地测试代码时,它会为较小长度的数组打印出正确的值,但会收到segmentation fault:11错误。

1 个答案:

答案 0 :(得分:2)

您的magic数字等于1,475,789,056,恰好适合带符号的32位整数。

但是,4 * magic是5,903,156,224,不是,并且溢出!

从技术上讲,C中的带符号整数溢出是未定义的行为,因此任何事情都可能在此时发生。但是通常发生的是,该值被简单地截断为32位,得到1,608,188,928,这就是最终为每个数组分配的字节数。

然后,您的for循环试图向该缓冲区写入1,475,789,056个四字节整数,它从数组的末尾开始运行并最终出现段错误(可能是在先破坏了内存中的某些其他值之后)。


要解决此问题,请将您的magic号存储在64位变量中,或者至少将其转换为64位类型,然后再传递给malloc()。我建议您使用size_t,因为它是actually intended for storing array sizes的类型,也是malloc()被定义为可以接受的类型。

当然,通常也不能保证size_t的位数超过32位-但是,如果没有,则无论如何都不会很幸运,因为您使用的是32位指针并且无论您可能拥有多少RAM,都无法在单个进程中分配超过4 GiB的内存(可能甚至没有)。