Что вызывает переполнение стека? - PullRequest
6 голосов
/ 20 сентября 2008

Вы можете подумать, что это совпадение, что тема моего вопроса похожа на название форума, но я на самом деле попал сюда, прибегая к помощи термина "переполнение стека".

Я использую сетевой симулятор OPNET, в котором я программирую на C. Я думаю, что у меня проблема с массивами большого размера. Кажется, что я бью своего рода ограничение выделения памяти. Это может иметь отношение к OPNET, Windows, памяти моего ноутбука или, скорее всего, к языку C. Проблема возникает, когда я пытаюсь использовать вложенные массивы с общим числом элементов, равным нескольким тысячам целых чисел. Я думаю, что я превышаю общий предел выделения памяти, и мне интересно, есть ли способ увеличить этот предел. Вот точное описание проблемы:

У меня в основном есть таблица маршрутизации. Давайте назовем это routing_tbl [n], что означает, что я поддерживаю 30 узлов (маршрутизаторов). Теперь для каждого узла в этой таблице я храню информацию. о многих (сотнях) доступных путях в массиве, называемом путями [p]. Опять же, для каждого пути в этом массиве я храню список узлов, которые ему принадлежат, в массиве с именем hops [h]. Итак, я использую как минимум nph целых чисел памяти, но эта таблица также содержит другую информацию. В той же функции я также использую другой вложенный массив, который также потребляет почти 40000 целых чисел. Как только я запускаю симуляцию, она перестает жаловаться на переполнение стека. Это работает, когда я уменьшаю общий размер таблицы маршрутизации. Как вы думаете, в чем причина проблемы и как ее можно решить? Очень признателен Али

Ответы [ 6 ]

10 голосов
/ 20 сентября 2008

Может помочь, если вы напишите какой-нибудь код. Измените вопрос, включив в него проблемную функцию и ошибку.

Между тем, вот очень общий ответ:

Двумя основными причинами переполнения стека являются: 1) рекурсивная функция или 2) выделение большого количества локальных переменных.

Рекурсия

если ваша функция вызывает себя, например:

int recurse(int number) {

    return (recurse(number));
}

Поскольку локальные переменные и аргументы функций хранятся в стеке, он будет заполнять стек и вызывать переполнение стека.

Большие локальные переменные

Если вы попытаетесь выделить большой массив локальных переменных, вы можете переполнить стек за один раз. Такая функция может вызвать проблему:

void hugeStack (void) {

    unsigned long long reallyBig[100000000][1000000000];

    ...
}

Существует довольно подробный ответ на этот аналогичный вопрос .

3 голосов
/ 20 сентября 2008

Каким-то образом вы используете много стека. Возможные причины: создание таблицы маршрутизации в стеке, передача ее в стек или генерация большого количества вызовов (например, путем рекурсивной обработки всего).

В первых двух случаях вы должны создать его в куче и передать указатель на него. В третьем случае вам нужно переписать ваш алгоритм в итерационной форме.

1 голос
/ 29 октября 2008

Многие операционные системы динамически расширяют стек по мере его использования. Когда вы начинаете запись по адресу памяти, который находится за пределами стека, ОС предполагает, что ваш стек только что увеличился, и выделяет ему дополнительную страницу (обычно 4096 Киб на x86 - ровно 1024 дюйма).

Проблема в том, что на x86 (и некоторых других архитектурах) стек увеличивается вниз , но массивы C увеличиваются вверх . Это означает, что если вы получите доступ к start большого массива, вы получите доступ к памяти, которая находится на расстоянии более чем одной страницы от края стека.

Если вы инициализируете свой массив в 0 , начиная с конца массива (это правильно, сделайте цикл for, чтобы сделать это), ошибки могут исчезнуть. Если они это сделают, это действительно проблема.

Возможно, вам удастся найти некоторые функции API OS для принудительного выделения стека или прагмы / флаги компилятора. Я не уверен, как это можно сделать переносимо, за исключением, конечно, использования malloc () и free ()!

1 голос
/ 20 сентября 2008

Это зависит от того, где вы объявили переменную.

Локальная переменная (т. Е. Объявленная в стеке ограничена максимальным размером кадра) Это ограничение используемого вами компилятора (и обычно его можно настроить с помощью флагов компилятора).

Динамически размещаемый объект (то есть тот, который находится в куче) ограничен объемом доступной памяти. Это свойство ОС (и технически может увеличить физическую память, если у вас умная ОС).

1 голос
/ 20 сентября 2008

Переполнение стека может произойти в C, когда число встроенных рекурсивных вызовов слишком велико. Возможно, вы вызываете функцию из себя слишком много раз?

Эта ошибка также может быть связана с выделением слишком большого количества памяти в статических объявлениях. Вы можете переключиться на динамическое распределение с помощью malloc (), чтобы решить эту проблему.

Есть ли причина, по которой вы не можете использовать отладчик в этой программе?

0 голосов
/ 20 сентября 2008

Вы вряд ли столкнетесь с переполнением стека с помощью не срезанной скомпилированной C, если только вы не сделаете что-то особенно вопиющее, например, неявную рекурсию или космическую утечку памяти. Тем не менее, ваш симулятор, вероятно, имеет пакет потоков, который наложит ограничения на размер стека. Когда вы запускаете новый поток, он выделяет кусок памяти для стека для этого потока. Вероятно, есть параметр, который вы можете установить где-нибудь, который устанавливает размер стека по умолчанию, или может быть способ динамически увеличивать стек. Например, в pthreads есть функция pthread_attr_setstacksize (), которую вы вызываете до запуска нового потока, чтобы установить его размер. Ваш симулятор может использовать или не использовать pthreads. Обратитесь к справочной документации вашего тренажера.

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