当一定大小时,Malloc 会导致稍后的段错误,否则无法运行? 但适用于 MacOS

问题描述

在此之前,我不是 C 语言中的佼佼者,为了改进这段代码我学到了很多东西,因此很多人对我所说的一些事情是不正确的。

背景

我继承了一些适用于较小数据集的代码。但是,我的任务是使用相同的技术调整此代码以在显着更大的数据集上运行(约 30 亿个值对 400 万个值)。

然而,我发现我需要将一些数组声明更改为 malloc 的,否则具有预定大小的分配会给我一个 segfault,因为这会发生在较大的数据集上,但它会起作用在较小的数据集上正确。

我很快遇到了一个问题,即所需的内存将远远大于我机器上的内存量(我的机器有 40 GB 而它需要大约 300 GB)。因此,我使用 mmap 将这些数组映射到我计算机上的文件。从 ints 到 ssize_ts 的一些更改之后以考虑大于 int 范围的索引位置,三部分程序的前两部分正在工作。但是,我在尝试让第三方工作时遇到了重大问题。我最近问了一个问题 here,尽管我接受了答案,但在运行代码后(花了大约 20 分钟,它再次出错。)

然而,我相信这可能不是问题的根源,但仍然不确定该怎么做,并且已经在这个特定问题上工作了大约一个月。

问题

虽然我不能完全确定这是正确的问题,但问题似乎是我需要分配一个 1,000,000 x 1,000 的稀疏数组(目前是整数,但很可能必须是 ssize_t) [注意:这是运行较小版本的真实数据集。真正的数据集很可能必须分配一个更大(仍然稀疏)的矩阵]。虽然这个数组太大而无法放入我的 1TB SSD 或内存中,但我认为由于它是一个稀疏数组,内核的过度承诺将能够生效并允许它成功发挥作用。然而,当我这样做时,我得到了同样的结果——常驻内存开始从大约 80% 上升到现在的 90%,然后被杀死。

发生了两件我无法理解的奇怪事情:

  1. 正如我之前问的问题所阐明的那样,我的上司能够在他的 Macbook pro 上运行该程序,内存为 16GB,而我的 40GB linux 机器被杀死(我假设内存不足......) .

  2. 当我将该数组大小减小到 1,000 x 100,000 时,仍然无法在内存或我的驱动器上表示,因为它只剩下大约 600 GB,它似乎通过了这一点,但后来甚至出现了段错误虽然我的上司能够很好地运行它。相比之下,但在我的计算机上运行的代码的早期部分中,superior 会以某种方式出现段错误。我认为唯一的区别是

  3. 我相信它必须对内存做一些事情,因为当我在较小的文件上运行改编的代码时,它能够工作。

尝试解决方

一位朋友建议我用 valgrind 运行它,虽然我不熟悉它试图让它运行。当我这样做时,它似乎适用于较小的数据集(它说我有一些内存泄漏,但它们都在可能出现内存问题的地方之后。)但它在较大的数据集上给了我一个 mmap 错误。我调查了这个问题,但无法解决

考虑尝试

我开始怀疑这与 linux 中的内存与 macos 相比超出承诺的方式有关,并且正在考虑尝试安装 hackintosh 以尝试让它运行。但是,我以前从未这样做过,我认为这会花费一些时间,因此如果我无法运行它,那将是非常不幸的。

相关代码

为 mmap 分配和释放:

double* newArrayDouble(ssize_t size,char* backupFile,int *filedestination) {
    printf("Trying to create %s with size %zu\n",backupFile,size);
    *filedestination = open(backupFile,O_RDWR | O_CREAT | O_Trunc,0644);
    if (*filedestination < 0) {
        perror("open Failed");
        exit(1);
    }
    // make sure file is big enough
    if (lseek(*filedestination,size*sizeof(double),SEEK_SET) == -1) {
        perror("seek to len Failed");
        exit(1);
    }
    if (write(*filedestination,"x",1) == -1) {
        perror("write at end Failed");
        exit(1);
    }
    if (lseek(*filedestination,SEEK_SET) == -1) {
        perror("seek to 0 Failed");
        exit(1);
    }

    double *array1 = mmap(NULL,PROT_READ | PROT_WRITE,MAP_SHARED,*filedestination,0);
    if (array1 == MAP_Failed) {
        perror("mmap Failed");
        exit(1);
    }

    return array1;
}
void freeArrayDouble(ssize_t size,double* array,int filedestination,char* backupFileName) {
    munmap(array,size*sizeof(double));
    close(filedestination);
    char filename[500];
    sprintf(filename,"rm %s",backupFileName);
    system(filename);
}

从 MMAP 文件中读取:

double* loadArrayDouble(ssize_t size,int *filedestination) {
    *filedestination = open(backupFile,O_RDWR | O_CREAT,0644);
    if (*filedestination < 0) {
        perror("open Failed");
        exit(1);
    }
    if (lseek(*filedestination,SEEK_SET) == -1) {
        perror("seek to len Failed");
        exit(1);
    }
    
    if (lseek(*filedestination,PROT_READ,0);
    if (array1 == MAP_Failed) {
        perror("mmap Failed");
        exit(1);
    }

    return array1;
}

矩阵分配:

IdxGroup = (ssize_t **) malloc(Num_Idx*sizeof(ssize_t*));

for (i = 0; i < Num_Idx; i++) {
     IdxGroup[i] = (ssize_t *)malloc(Num_Idx*sizeof(ssize_t));
}

^ 我将其更改为 ssize_t 因为我意识到稍后它必须是 ssize_t 但无论如何它都不起作用。

注意:我相信启用了过度承诺,​​因为我可以分配一个非常大的数组(授予它只是 main 和 malloc,所以我不确定编译器是否删除它?)并且我在所问的问题中运行了命令之前。

感谢您的帮助!请让我知道是否还有我应该包含的信息。这很难,因为代码太多,我真的不知道为什么会坏。

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)