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