Ошибка сегментации при больших размерах массива


116

Следующий код дает мне ошибку сегментации при запуске на машине 2 ГБ, но работает на машине 4 ГБ.

int main()
{
   int c[1000000];
   cout << "done\n";
   return 0;
}

Размер массива всего 4 Мб. Есть ли ограничение на размер массива, который можно использовать в c ++?

Ответы:


130

Вероятно, здесь просто переполнение стека. Массив слишком велик, чтобы поместиться в адресное пространство стека вашей программы.

Если вы разместите массив в куче, все будет в порядке, если на вашем компьютере достаточно памяти.

int* array = new int[1000000];

Но помните, что для этого вам потребуется delete[]массив. Лучшим решением было бы использовать std::vector<int>и изменить его размер до 1000000 элементов.


3
Спасибо за ответ, но не могли бы вы объяснить мне, почему массивы выделяются в стеке и почему не в основной памяти программы.
Mayank

18
Данный код выделяется в стеке, потому что он задан как массив с постоянным количеством элементов во время компиляции. Значения помещаются в кучу только с помощью malloc, new и т. Д.
Сет Джонсон

6
Все автоматические переменные размещаются в стеке. Если вы посмотрите на дизассемблирование, вы увидите размер ваших локальных переменных, вычтенных из указателя стека. Когда вы вызываете malloc, calloc или любую из функций памяти, функции идут и находят блоки памяти, достаточно большие, чтобы удовлетворить ваш запрос.
повтор

@ Чарльз, почему мы могли выделить больше памяти из кучи, а не из стека? Насколько я понимаю, и стек, и куча перемещаются в противоположном направлении в выделенном адресном пространстве в памяти.
саураб агарвал

2
@saurabhagarwal Куча не двигается. Это даже не непрерывная область памяти. Распределитель просто возвращает свободный блок памяти, соответствующий вашим требованиям к размеру. Что и где находятся стек и куча?
phuclv

56

В C или C ++ локальные объекты обычно размещаются в стеке. Вы выделяете в стеке большой массив, больше, чем стек может обработать, поэтому вы получаете stackoverflow.

Не размещайте его локально в стеке, вместо этого используйте другое место. Этого можно достичь, сделав объект глобальным или разместив его в глобальной куче . Глобальные переменные подходят, если вы не используете их из других единиц компиляции. Чтобы это не произошло случайно, добавьте спецификатор статического хранилища, в противном случае просто используйте кучу.

Это будет выделено в сегменте BSS, который является частью кучи:

static int c[1000000];
int main()
{
   cout << "done\n";
   return 0;
}

Это будет выделено в сегменте DATA, который также является частью кучи:

int c[1000000] = {};
int main()
{
   cout << "done\n";
   return 0;
}

Это будет выделено в каком-то неопределенном месте в куче:

int main()
{
   int* c = new int[1000000];
   cout << "done\n";
   return 0;
}

Если вы используете третий шаблон, выделение памяти в куче, не забудьте на каком-то этапе удалить [] указатель, иначе вы потеряете память. Или посмотрите на умные указатели.
davidA 05

8
@meowsqueak Конечно, это хорошая практика deleteвезде, где вы выделяете new. Но если вы уверены, что выделяете память только один раз (как в main), в этом нет необходимости - память гарантированно будет освобождена при выходе из main даже без явного указания delete.
Gunther Piez 05

'at'drhirsch (как вообще у вас получается персонаж at?) - да, справедливый комментарий. Поскольку OP кажется новым для языка, я просто хотел убедиться, что они и все, кто увидит ваш хороший ответ, знали о последствиях третьего варианта, если он используется в целом.
davidA 05

15

Кроме того, если вы работаете в большинстве систем UNIX и Linux, вы можете временно увеличить размер стека с помощью следующей команды:

ulimit -s unlimited

Но будьте осторожны, память - это ограниченный ресурс, и с большой мощностью приходят большие обязанности :)


1
Это решение, но я советую всем быть предельно осторожными при снятии ограничений по умолчанию на размер стека программы. Вы не только испытаете серьезное падение производительности, но и ваша система может выйти из строя. Например, я попытался отсортировать массив с 16 000 000 целочисленных элементов с помощью быстрой сортировки на машине с 4 ГБ ОЗУ, и моя система почти перестала работать. LOL
rbaleksandar

@rbaleksandar Я думаю, что ваша программа размером ~ 16 МБ почти убивает вашу машину, потому что вы работали с несколькими копиями массива (может быть, по одной на вызов функции?) Попробуйте реализацию с большей памятью;)
RSFalcon7

Я почти уверен, что обработка массивов в порядке, поскольку я передаю по ссылке, а не по значению. То же самое происходит с пузырьковой сортировкой. Черт, даже если моя реализация быстрой сортировки отстойная, пузырьковая сортировка - это то, что вы не можете реализовать неправильно. LOL
rbaleksandar

LOL, вы можете попробовать Radix sort или просто использовать std :: sort :)
RSFalcon7

1
Без шансов. Это лабораторное задание. : D
rbaleksandar

3

Ваш массив выделяется в стеке, в этом случае попытайтесь выделить массив того же размера с помощью alloc.


3

Потому что вы храните массив в стеке. Вы должны хранить его в куче. См. Эту ссылку, чтобы понять концепцию кучи и стека.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.