Limite dello stack

10

Recentemente ho testato il limite di uno stack su tre dispositivi con SO diversi (per limite, intendo il numero massimo di livelli che può avere lo stack), e ho notato che ogni volta quando raggiungo i livelli 2 ^ 16 mi dà errore di overflow, e quando inserisco 2 ^ 16-1 funziona correttamente.

Quindi la mia domanda è - è vero? Lo stack ha il limite massimo 2 ^ 16-1 per definizione o dipende dal sistema operativo?

    
posta Anonymus 26.01.2017 - 14:55
fonte

2 risposte

20

È uno specifico sistema operativo (e specifico del computer) e su alcuni sistemi operativi hai alcuni modi per configurare (e persino aumentare) il limite. È anche specifico del compilatore (o specifico per l'implementazione del tuo linguaggio di programmazione), dal momento che alcuni compilatori (incluso il recente GCC per alcuni limitato tipo di codice C) sono in grado di ottimizzare alcune chiamate a coda .

(alcune specifiche del linguaggio di programmazione richiedono ottimizzazioni delle chiamate tail, ad es. R5RS )

Non sono sicuro che la tua domanda abbia un senso (e certamente non il tuo limite 2 16 ). Sul mio desktop Linux (Debian / Sid / x86-64, kernel Linux 4.9, 32Gb RAM, Intel i5-4690S), potrei avere un stack di chiamate fino a 8 megabyte (e potrei aumentare il limite, se lo volessi davvero).

Multi-threading e ASLR sta rendendo la tua domanda molto più complessa . Vedi per es. pthread_attr_setstack (3) . Leggi anche su stack divisi (spesso usato da Vai implementazioni) e su stile di passaggio continuo . Vedi anche questa risposta.

Per quel che vale, ho appena provato il seguente codice C99 (e anche 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

e sono stato in grado di eseguire quel programma recur (compilato con GCC 6 come gcc -Wall -O recur.c -o recur ) come recur 161000 (molto al di sopra del limite 2 16 ). Con recur 256000 ha funzionato anche. Con recur 456000 è andato in crash (con un overflow dello stack per il livello x=272057 ). Non ho la pazienza per altri test. Prova sul tuo computer. Non dimenticare di chiedere ottimizzazioni.

Una regola empirica (per desktop, laptop, tablet) potrebbe essere quella di mantenere lo stack delle chiamate inferiore a un megabyte.

Passando anche -fstack-usage a gcc I'm ottenere il seguente file recur.su (i numeri sono espressi in byte, coerenti con il mio intuizione del limite di stack di 8Mb; non dimenticare il frame di chiamata main , e ancora più importante il layout dello stack iniziale, installato dal kernel quando si fa execve(2) ..., per crt0 ):

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

PS. Il mio Arduino ha un Atmega328 con solo 2Kbyte di RAM, quindi certamente non si ripeterà più di tanto. Immagino che solo poche centinaia di frame dello stack siano praticamente possibili su Arduinos.

    
risposta data 26.01.2017 - 14:58
fonte
3

Dimensione dello stack per il thread principale di un processo Windows è impostato dal linker. L'impostazione predefinita è 1 MB ma può essere regolata con l'opzione / STACK. I thread creati in seguito possono utilizzare il parametro dwStackSize della funzione CreateThread.

Quindi, se stai provando vari sistemi operativi Windows, tutti hanno avuto le stesse dimensioni di stack predefinite almeno da NT4.0.

    
risposta data 26.01.2017 - 22:59
fonte

Leggi altre domande sui tag