Quanto consumo di stack è eccessivo?

10

Ultimamente, quando scrivo C o C ++, dichiarerò tutte le mie variabili nello stack solo perché è un'opzione, a differenza di Java.

Tuttavia, ho sentito dire che è una cattiva idea dichiarare grandi cose in pila.

  1. Perché esattamente è così? Immagino che l'overflow dello stack sia coinvolto, ma non sono molto chiaro sul perché ciò avvenga.
  2. Quanto materiale nello stack è troppo?

Non sto cercando di mettere 100 MB di file nello stack, solo una dozzina di kilobyte array da usare come buffer di stringa o altro. È troppo l'uso dello stack?

(Scusa se duplicato, la ricerca dello stack continua a fornire riferimenti a Stack Overflow. Non c'è nemmeno un tag stack di chiamate, ho appena usato quello astratto.)

    
posta Elliot Way 20.02.2016 - 23:00
fonte

4 risposte

9

Dipende dal tuo sistema operativo. Su Windows, la dimensione massima tipica per uno stack è 1 MB, mentre è di 8 MB su un tipico Linux moderno, sebbene tali valori siano regolabili in vari modi. Se la somma delle tue variabili stack (inclusi i costi generali di basso livello come gli indirizzi di ritorno, gli argomenti basati su stack, i valori di restituzione dei segnaposto e i byte di allineamento) nell'intero stack di chiamate supera questo limite, ottieni un overflow dello stack, che in genere riduce il tuo programma senza alcuna possibilità di recupero.

Di solito alcuni kilobyte vanno bene. Decine di kilobyte sono pericolosi perché iniziano a riassumere. Centinaia di kilobyte sono una pessima idea.

    
risposta data 20.02.2016 - 23:14
fonte
4

L'unica risposta valida è vaga: "è troppo quando lo stack trabocca".

A meno che tu non abbia il controllo completo sull'implementazione di ogni linea di codice tra il punto di ingresso del programma e la funzione in questione, non puoi fare ipotesi sulla quantità di stack disponibile. Ad esempio, non è possibile garantire che la chiamata a questa funzione non causerà mai un overflow dello stack:

void break_the_camels_back()
{
    int straw;
    ...
}

Lo stack 8 MiB di default sugli Unix moderni è un bel po 'di spazio in termini di stack, specialmente per qualcuno come me che è abbastanza di un geezer per ricordare le CPU con puntatori stack a 8 bit. La realtà pratica è che difficilmente riuscirai a farcela senza provarci. Se lo fai, il superamento del limite dello stack viene solitamente considerato una violazione della segmentazione e i sistemi con una gestione della memoria sufficiente a rilevarlo invieranno un SIGSEGV quando ciò accade.

Hai un paio di opzioni. Per prima cosa non indovinare quanto stack è disponibile e chiedi al sistema. Qualunque cosa sia conforme a POSIX avrà una funzione getrlimit(2) che ti indicherà il limite superiore. RLIMIT_STACK è il limite specifico che desideri. Il secondo è monitorare il livello di stack utilizzato dai programmi e prendere decisioni sulle variabili automatiche rispetto all'allocazione dinamica della memoria in base a ciò. Per quanto ne so, non esistono funzioni standard per determinare la quantità di stack utilizzata, ma programmi come valgrind possono analizzarlo per te.

    
risposta data 21.02.2016 - 17:03
fonte
2

Bene 1 MB è una buona stima per * nix. La ricorsione può essere una delle ragioni principali per l'overflow dello stack in combinazione con le allocazioni dello stack. Tuttavia, nella maggior parte dei casi gli oggetti di dio che sembrerebbero troppo grandi per essere messi in pila sono progettati bene per gestire la memoria interna sull'heap e utilizzare lo stack solo come modo per essere automaticamente distrutti quando viene lanciato lo stack. Il distruttore libererà gli enormi blocchi di memoria gestiti internamente. I contenitori std sono progettati in questo modo e anche i puntatori condivisi / unici sono progettati in questo modo.

L'importante è non allocare grandi blocchi di mem grezzi sullo stack come char [1024 * 1024] e progettare classi per racchiudere le allocazioni dell'heap e usare lo stack solo per la comodità di chiamare automaticamente il distruttore.

    
risposta data 21.02.2016 - 14:37
fonte
1

Se si assegna un array di dire 10.000 byte nello stack, allora tale array ha una dimensione limitata. 10.000 possono essere molto, ma se hai bisogno di 10,001 byte allora il tuo programma può andare in crash o peggio. Quindi in questa situazione, vuoi qualcosa che si adatta alle dimensioni che ti servono e che qualcosa non sarà in pila.

Gli array di dimensioni fisse per i buffer di stringa sullo stack non sono un problema perché mantengono la memoria in pila, sono un problema perché i buffer a dimensione fissa sono un problema fatale che aspetta di accadere.

Ma se usi C ++ e dichiari ad esempio una std :: string o una std :: vec nello stack, allora quello che è nello stack sarà in realtà di una dimensione fissa e piccola. I dati effettivi verranno archiviati nell'heap. È possibile archiviare un milione di caratteri in un'istanza std :: string e saranno necessari solo una piccola quantità di dati (in genere da 8 a 24 byte, a seconda dell'implementazione) nello stack e un milione di byte nello heap.

    
risposta data 01.01.2019 - 18:46
fonte

Leggi altre domande sui tag