Межа стека


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 для обмеженого виду коду С) здатні оптимізувати деякі хвостові дзвінки .

(деякі специфікації мови програмування вимагають оптимізації виклику, наприклад R5RS )

Я не впевнений, що ваше питання має сенс (і, звичайно, не ваша межа 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файл (числа в байтах, в відповідно до мого 8Mb стеки межі інтуїцією, не забувайте 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.

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