Есть ли ограничение на объем памяти стека? - PullRequest
9 голосов
/ 06 мая 2010

Я проходил через одну из тем. Сбой программы, потому что он объявил массив из 10 ^ 6 локально внутри функции.

Причиной была ошибка выделения памяти в стеке, приводящая к сбою.

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

Теперь давайте предположим, стек растет вниз и накапливается вверх.

У нас есть:

--- СТЕК ---

-------------------

--- КУЧА ----

Теперь я считаю, что если в стеке происходит сбой при распределении, он также должен потерпеть неудачу в куче.

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

Ответы [ 6 ]

6 голосов
/ 06 мая 2010

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

Обычно значения по умолчанию (если не установлены вручную) составляют около 1 МБ для текущих языков , что вполне достаточно, если вы не делаете что-то, что обычно не рекомендуется (например, выделяете огромные массивы в стеке)

5 голосов
/ 06 мая 2010

Все зависит от того, какой язык и компилятор вы используете. Но программы, скомпилированные, например, с C или C ++, выделяют стек фиксированного размера при запуске программы. Размер стека обычно может быть указан во время компиляции (на моем конкретном компиляторе он по умолчанию равен 1 МБ).

4 голосов
/ 16 марта 2016

Вопреки всем ответам на данный момент, в Linux с GCC (и я полагаю, что это верно для всех современных операционных систем POSIX), максимальный размер стека - это предел безопасности, установленный операционной системой, который может быть легко снят.

Я создал небольшую программу, которая рекурсивно вызывает функцию, пока в стеке не выделяется не менее 10 ГБ, не ожидает ввода данных на терминале, а затем благополучно возвращается от всех рекурсивных вызовов до main.

#include <stdio.h>
#include <string.h>
#include <sys/time.h>
#include <sys/resource.h>

void grow(unsigned cur_size)
{
    if(cur_size * sizeof(int) < 10ul*1024ul*1024ul*1024ul) {
        unsigned v[1000];
        v[0] = cur_size;
        for(unsigned i = 1; i < 1000; ++i) {
            v[i] = v[i-1] + 1;
        }

        grow(cur_size + 1000);

        for(unsigned i = 0; i < 1000; ++i) {
            if(v[i] != cur_size + i)
                puts("Error!");
        }
    } else {
        putchar('#');
        getchar();
    }
}

int main()
{
    struct rlimit l;
    l.rlim_max = RLIM_INFINITY;
    l.rlim_cur = RLIM_INFINITY;
    setrlimit(RLIMIT_STACK, &l);

    grow(0);
    putchar('#');
    getchar();
}
2 голосов
/ 06 мая 2010

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

Мне, конечно, иногда приходилось увеличивать максимум.

1 голос
/ 06 мая 2010

Может быть, не очень хороший ответ, но дает вам немного более детальный взгляд на то, как windows в целом управляет памятью: Расширение границ Windows

1 голос
/ 06 мая 2010

Да, в большинстве языков есть ограничение на размер стека. Например, в C / C ++, если у вас неправильно написанная рекурсивная функция (например, неверный базовый случай), вы переполните стек. Это потому, что, игнорируя хвостовую рекурсию , каждый вызов функции создает новый кадр стека , который занимает место в стеке. Сделайте это достаточно, и вам не хватит места.

Запуск этой программы на C в Windows (VS2008) ...

void main()
{
    main();
}

... приводит к переполнению стека:

Unhandled exception at 0x004113a9 in Stack.exe: 0xC00000FD: Stack overflow.

...