Получение «сбоя сегментации: 11» после malloc () 12 ГБ памяти, несмотря на наличие достаточного объема памяти (32 ГБ) - PullRequest
0 голосов
/ 01 июля 2019

У меня есть программа, которой нужно выделить 2 целых массива длиной 1,5 миллиарда.Это для задачи кодирования (https://projecteuler.net/problem=282), и нет возможности обойти использование таких больших массивов (если есть, пожалуйста, не говорите мне; я должен найти ответ самостоятельно). Онидолжны быть 32-разрядными целыми числами, поскольку их значения находятся в диапазоне от 0 до 1,5 млрд. 3 млрд. целых чисел занимают около 12 гигабайт, поэтому я решил использовать экземпляр EC2 r5.xlarge с 32 гигабайтами памяти, но я получаю segmentation faultошибка в моем коде C. Когда я тестирую код локально, он работает для меньших массивов, но получает сообщение об ошибке segmentation fault:11 в полноформатной версии.

Я посмотрел онлайн и пытался изменить настройки вulimit с ulimit -m 15000000 и ulimit -v 15000000 (оба числа в килобайтах). Они уже были установлены на 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

Я получаю ошибку segmentation fault в своем коде C на экземпляре EC2. Когда я проверяю код локально, он выводит правильное значение для массивов меньшей длины, но получает ошибку segmentation fault:11.

1 Ответ

2 голосов
/ 01 июля 2019

Ваше magic число равно 1 475 789 056, что отлично вписывается в 32-разрядное целое число со знаком.

Однако 4 * magic равно 5 903 156 224, что не происходит, и переполняется!

Технически, целочисленное переполнение со знаком в C - неопределенное поведение, поэтому все, что может произойти в этот момент.Но то, что обычно происходит, так это то, что значение просто усекается до 32 бит, что дает 1 608 188 928, и это количество байтов, которое вы в конечном итоге выделяете для каждого массива.

А затем ваш for loop, который пытается записать 1,475,789,056 четырехбайтовых целых чисел в этот буфер, запускается из конца массива и, в конечном итоге, вызывает ошибки (возможно, после повреждения некоторых других значений в памяти).


Чтобы исправить этосохраните ваш номер magic в 64-битной переменной или, по крайней мере, преобразуйте его в 64-битный тип, прежде чем передать его в malloc().Я бы порекомендовал использовать size_t, так как это тип , предназначенный для хранения размеров массивов , а также тип, который malloc() определен для принятия.

Конечно, в общем, нет гарантии, что size_t имеет более 32 бит, либо - но если этого не произойдет, то вам все равно не повезло, так как вы используете 32-битные указатели и не будетекогда-либо сможет выделить более 4 ГБ памяти (и, возможно, даже не это) в одном процессе, независимо от того, сколько общего объема оперативной памяти у вас может быть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...