Предел стека

10

Недавно я протестировал ограничение стека на трех устройствах с разными ОС (под лимитом я подразумеваю максимальное количество уровней, которое может иметь стек), и я заметил, что каждый раз, когда я достигаю 2 ^ 16 уровней, это дает мне ошибка переполнения, и когда я ставлю 2 ^ 16-1, он работает правильно.

Итак, мой вопрос - это правда? У стека есть максимальный предел 2 ^ 16-1 по определению или это зависит от ОС?

Анонимус
источник
5
here i mean by limit the maximum number of levels that can the stack haveкакой уровень?
tkausl
3
Как вы это тестируете? Вы используете 2-байтовый (dword) в качестве ввода?
pro3carp3
6
Какой язык программирования вы используете? Такое резкое ограничение на фиксированное число указывает на то, что оно является преднамеренным ограничением времени выполнения вашего языка, а не размером стека, выделенным ОС. Например, Python, по-видимому, применяет ограничение по умолчанию в 1000, чтобы предотвратить попадание в реальное переполнение стека (восстановление из-за переполнения реального стека затруднительно)
CodesInChaos

Ответы:

20

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

(некоторые спецификации языка программирования требуют оптимизации хвостового вызова, например R5RS )

Я не уверен, что ваш вопрос имеет смысл (и, конечно, не ваш 2 16 предел). На моем рабочем столе Linux (Debian / Sid / x86-64, ядро ​​Linux 4.9, 32 ГБ ОЗУ, Intel i5-4690S) у меня может быть стек вызовов до 8 мегабайт (и я мог бы увеличить этот предел, если бы я действительно хотел ).

Многопоточность и ASLR делает ваш вопрос гораздо сложнее . Смотрите, например, pthread_attr_setstack (3) . Читайте также о разделенных стеках (часто используемых реализациями Go ) и о стиле передачи продолжения . Смотрите также этот ответ.

Для чего это стоит, я только что попробовал следующий код C99 (а также C11):

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void recfun(int x, int d) {
  printf("start recfun x=%d d=%d\n", x, d);
  fflush(NULL);
  if (d>0)
    recfun(x+1, d-1);
  printf("end recfun x=%d d=%d\n", x, d);
}

int main(int argc, char**argv) {
  int md = argc>1?atoi(argv[1]):10000;
  printf ("start md=%d\n", md);
  recfun(0, md);
  printf("end md=%d clock=%ld µs\n", md, clock());
}    
// eof recur.c

и я смог запустить эту recurпрограмму (скомпилированную с GCC 6 as gcc -Wall -O recur.c -o recur) recur 161000 (намного выше вашего предела в 2 16 ). С recur 256000этим тоже работал. С recur 456000ним разбился (с переполнением стека для уровня x=272057). У меня нет терпения для других тестов. Попробуйте это на своем компьютере. Не забудьте спросить об оптимизации.

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

Переходя также -fstack-usage к gcc получению следующего recur.suфайла (числа в байтах, в соответствии с моей интуицией ограничения стека в 8 Мбайт; не забывайте mainфрейм вызова и, что более важно, начальную компоновку стека, установленную ядром при выполнении execve (2). ) ..., для crt0 ):

 recur.c:5:10:recfun    32  static
 recur.c:13:9:main  16  static

PS. Мой Arduino имеет Atmega328 только с 2 Кбайт оперативной памяти, поэтому, конечно, не может повторить так много. Я предполагаю, что на Arduinos возможно практически несколько сотен фреймов стека.

Василий Старынкевич
источник
3

Размер стека для основного потока процесса Windows задается компоновщиком. Значение по умолчанию составляет 1 МБ, но его можно настроить с помощью переключателя / STACK. Потоки, созданные позже, могут использовать параметр dwStackSize функции CreateThread.

Так что ... если вы тестируете различные ОС Windows, у них у всех одинаковый размер стека по умолчанию, начиная как минимум с NT4.0.

Эрик
источник