Помилка сегментації на великих розмірах масиву


116

Наступний код дає мені помилку сегментації під час роботи на 2Gb машині, але працює на 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
Даний код виділяє в стеці, тому що він вказаний як масив з постійною кількістю елементів під час компіляції. Значення ставляться на купу лише з молоком, новим і т. Д.
Сет Джонсон

6
Усі автоматичні перекладні знаки виділяються на стеку. Якщо ви подивитесь на розбірливий, ви побачите розмір локальних змінних, віднятих у вказівника стека. Коли ви викликаєте malloc або calloc або будь-який з функцій пам'яті, fuctions переходять і знаходять блоки пам'яті, досить великі, щоб сатаїзувати ваш запит.
повтор

@Charles чому ми можемо виділити більше пам’яті з купи, а не зі стека? з мого розуміння, і стек, і купа рухаються в зворотному напрямку у виділеному адресному просторі в пам'яті.
saurabh agarwal

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

8
@meowsqueak Звичайно, це є хорошою практикою для deleteвсіх, де ви виділяєте new. Але якщо ви впевнені, що ви виділяєте пам'ять лише один раз (як і в основному), вона категорично не потрібна - пам'ять гарантовано буде звільнена на виході основної навіть без явного delete.
Гюнтер П'єз

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

15

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

ulimit -s unlimited

Але будьте обережні, пам'ять - це обмежений ресурс і з великою потужністю приходять великі обов'язки :)


1
Це рішення, але я раджу всім бути вкрай обережними при усуненні цього обмеження за замовчуванням на розмір стека програми. Ви відчуєте не тільки сильний спад продуктивності, але і ваша система може вийти з ладу. Наприклад, я спробував сортувати масив із 16 000 000 цілих елементів з quicksort на машині з 4 Гб оперативної пам’яті, і моя система була майже вбита. LOL
rbaleksandar

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

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

LOL ви можете спробувати radix сортування, або просто використовувати std :: sort :)
RSFalcon7

1
Немає шансу. Це лабораторне завдання. : D
rbaleksandar

3

У цьому випадку масив виділяється на стек, намагаючись виділити масив однакового розміру за допомогою alloc.


3

Тому що ви зберігаєте масив у стеку. Ви повинні зберігати його в купі. Перейдіть за цим посиланням, щоб зрозуміти поняття купи та стека.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.