【问题标题】:Allocating an integer array dynamically with 1 billion elements in C在 C 中动态分配具有 10 亿个元素的整数数组
【发布时间】:2020-07-27 14:22:20
【问题描述】:

在 C 中,我试图创建一个包含 1,000,000,000(10 亿)个元素的整数数组。我试过用;

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
#include <time.h>

#define population 1000000000

int numberOfHandshaking;

int main(int argc, char **argv) {
    printf("******************************\n");
    printf("     FRIEND CIRCLE QUERIES\n");
    printf("******************************\n\n");

    FILE *fPointer;
    fPointer = fopen("C:\\Users\\ASUS\\Desktop\\AdvProTech2\\uebung_6\\Ass13in.txt", "r");

    fscanf(fPointer, "%d", &numberOfHandshaking); // Reads the first line
    printf("numberOfHandshakings: %d\n", numberOfHandshaking);

    int *persons = malloc((population + 1) * sizeof(int));

    for (int i = 0; i < 127; i++) {
        printf("persons[%d]= %d \n", i, persons[i]);
    }

    printf("\n\n\n");
    return 0;
}

它在编译时不会出错,但在尝试到达元素时会崩溃。谁能帮我?

【问题讨论】:

  • 作业要求人口为10^9
  • 除非您的内存供应至少有那么多连续内存,否则malloc 将始终返回 NULL,如果您不处理这种情况,是的,您的程序可能会崩溃。
  • 这暗示你不应该分配数组,而是有更好的算法来解决它。
  • 您可能对稀疏数组之类的东西感兴趣,理论上所有元素都存在,但实际上只有填充的元素会使用数据类型的全部内存大小
  • 很可能你的家庭作业可以在不分配那么大的数组的情况下解决。显示作业。

标签: c memory integer malloc allocation


【解决方案1】:

在处理此类荒谬的数字时,请将您的程序编译为 64 位。或者只是编写更好的代码,因为我可以向您保证,您不需要像那样分配的数组。

【讨论】:

  • 我如何编译成 64 位?
  • @jensoncan,取决于您的编译器。 gcc 使用 -march=x64cl 使用交叉编译器模式,您可以在其中选择主机架构(可能是 x64)和目标平台(x64)并选择编译器,例如,@987654326 @
  • 如果他不是在64bit的机器上运行(看起来,因为他在运行windows)如果windows检测到64bit兼容架构,那么它应该安装了64bit版本。
  • @jensoncan,64 位不是您可以在编译时选择的,您需要 64 位硬件才能运行它。如果你不能在你的电脑上运行,那么编译(强制编译器编译为 64 位)是没有意义的。
  • 你不知道你在说什么,请不要在新手担心的地方传播错误信息。
【解决方案2】:

首先,你没有说你在哪个架构中尝试这种方法。其次,你没有说你使用的是什么操作系统。你只说你在尝试malloc(3)一个十亿的数组ints。

三思而后行:包含 1 000 0000 001 int 元素的单个数组的大小为 4 000 000 004。如果您尝试在 32 位架构中处理此问题,则您要求系统仅为您的阵列分配完整的虚拟内存空间(即 4Gb)。很可能你有一个非常硬的限制,阻碍你分配这么多的内存。

在 64 位架构中,您有足够的地址来处理它,但同样,您的操作系统可能会拒绝创建这种大小(或您的系统可以处理的虚拟内存量)的单个连续映射。最有可能的是,您将无法获得该内存。我看到您正在 Windows 中运行它(通过您用于文件名的路径)所以很可能您甚至无法检查每个进程可以处理多少内存。

我已经在 FreeBSD 64 位架构中测试了您的程序,在该架构中我有以下限制(我不得不承认我已经对它们进行了一些调整以处理您的用户帐户问题,因为多用户系统中的普通用户是默认情况下从未授予此类限制):

$ ulimit -a
number of pseudoterminals            (-P) unlimited
socket buffer size       (bytes, -b) unlimited
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) 33554432
file size               (blocks, -f) unlimited
max kqueues                     (-k) unlimited
max locked memory       (kbytes, -l) unlimited
max memory size         (kbytes, -m) unlimited
open files                      (-n) 230121
pipe size            (512 bytes, -p) 1
stack size              (kbytes, -s) 524288
cpu time               (seconds, -t) unlimited
max user processes              (-u) 12042
virtual memory          (kbytes, -v) unlimited
swap size               (kbytes, -w) unlimited

(如您所见,我的最大数据段大小限制为 33Gb,因此,如果我要求 100 亿个元素的数组,我失败了,需要说这个限制是由内核强加的,我不能提高它——即使是根)

  • 当我这样做时,我得到了一个SIGSEGV,因为fopen(3) 返回的文件指针给了NULL(文件不存在,另一件事你没有在你的程序中检查)所以程序是fscanf(3) 呼叫中止。 注意:您需要检查调用的返回值是否有错误。
  • 在那之后,我完全能够毫无问题地运行(并且确实分配了十亿 -- 加一个 -- 元素数组)。 FreeBSD 程序从头到尾在 0.001 秒内运行,因为它不必在一个块中分配所有内存(实际上,它不必全部分配,因为您只使用数组的前 126 个元素,所以实际上,您只会分配一页这样的内存,即 504 字节的内存。
$ pru
*****************************************
     THIS WAS FRIEND CIRCLE QUERIES
*****************************************

numberOfHandshakings: 99885
persons[0]= 0 
persons[1]= 0 
persons[2]= 0 
[...]
persons[123]= 0 
persons[124]= 0 
persons[125]= 0 
persons[126]= 0 



然后我把最大虚拟内存空间固定为4Gb,重复测试:

$ pru
*****************************************
     THIS WAS FRIEND CIRCLE QUERIES
*****************************************

numberOfHandshakings: 99885
malloc failed: Cannot allocate memory

这一次,ulimit -a 的结果是:

$ ulimit -a
number of pseudoterminals            (-P) unlimited
[... same as before ]
max user processes              (-u) 12042
virtual memory          (kbytes, -v) 4194304 <<<<<< 4Gb virtual memory.
swap size               (kbytes, -w) unlimited

您的程序,经过我对其进行的修改以能够处理对fopen()malloc() 的调用返回的错误是:

#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#define population 1000000000

int numberOfHandshaking;

int main(int argc, char **argv)
{
    printf("*****************************************\n");
    printf("     THIS WAS FRIEND CIRCLE QUERIES\n");
    printf("*****************************************\n\n");

    FILE *fPointer;
    fPointer =
        fopen("Ass13in.txt", /* I changed this, my apologies */
            "r");

    if (fPointer == NULL) {
        printf("couldn't open file: %s\n", strerror(errno));
        exit(1);
    }

    fscanf(fPointer, "%d", &numberOfHandshaking); // Reads the first line
    printf("numberOfHandshakings: %d\n", numberOfHandshaking);

    int *persons = malloc((population+1) * sizeof(int));

    if (persons == NULL) {
        printf("malloc failed: %s\n", strerror(errno));
        exit(1);
    }

    for (int i=0; i<127; i++){
        printf("persons[%d]= %d \n", i, persons[i]);
    }

    printf("\n\n\n");
    return 0;
}

它运行良好! :)

注意:

在您的程序中,您不需要使用 #include 文件。它们是:

#include <ctype.h>
#include <math.h>
#include <time.h>

【讨论】:

    【解决方案3】:

    如果您在运行前不知道所需的缓冲区大小,则在分配内存时,较小的块比非常大的块更可取,因为缺少可用的连续内存而失败的可能性很高。

    calloc/malloc开始,然后使用realloc

    // return '*str' after number of bytes realloc'ed to 'size'
    static char * ReSizeBuffer(char **str, unsigned int size)
    {
        char *tmp=NULL;
    
        if(!(*str)) return NULL;
    
        if(size == 0)
        {
            free(*str);
            return NULL;
        }
    
        tmp = (char *)realloc((char *)(*str), size);
        if(!tmp)
        {
            free(*str);
            return NULL;
        }
        *str = tmp;
    
        return *str;
    }
    

    【讨论】:

    • 但这甚至没有尝试解决问题!!!!只是为了拖延它!
    猜你喜欢
    • 2019-07-19
    • 1970-01-01
    • 2017-01-02
    • 1970-01-01
    • 1970-01-01
    • 2014-06-19
    • 2018-09-17
    • 2011-04-15
    • 2018-12-28
    相关资源
    最近更新 更多