Dimensione massima dello stack del programma in C / C ++


115

Voglio fare DFS su un array 100 x 100. (Supponiamo che gli elementi dell'array rappresentino i nodi del grafo) Quindi, supponendo il caso peggiore, la profondità delle chiamate di funzione ricorsive può arrivare fino a 10000 con ogni chiamata che richiede fino a 20 byte. Quindi è fattibile significa che c'è una possibilità di stackoverflow?

Qual è la dimensione massima dello stack in C / C ++?

Specificare per gcc sia per
1) cygwin su Windows
2) Unix

Quali sono i limiti generali?


11
Sai che puoi implementare la ricerca in profondità senza ricorsione, giusto?
Sebastian

4
No, non lo so, per favore spiega.
avd

1
Ho fatto un piccolo esempio di DFS senza ricorsione nella mia risposta
Andreas Brinck

56
più uno per una domanda sull'effettivo overflow dello stack
Sam Watkins

3
@SamWatkins sì, uno dei problemi più grandi per me con il nome Stack Overflow è che potrei cercare "stack overflow" su Google e finire in questo sito Web, ma non necessariamente / meno probabile in domande sugli stack overflow ...
lalilulelost

Risposte:


106

In Visual Studio la dimensione dello stack predefinita è 1 MB, penso, quindi con una profondità di ricorsione di 10.000 ogni stack frame può essere al massimo ~ 100 byte, il che dovrebbe essere sufficiente per un algoritmo DFS.

La maggior parte dei compilatori, incluso Visual Studio, consente di specificare la dimensione dello stack. Su alcuni (tutti?) Gusti Linux la dimensione dello stack non fa parte dell'eseguibile ma una variabile d'ambiente nel sistema operativo. È quindi possibile controllare la dimensione dello stack con ulimit -se impostarlo su un nuovo valore con, ad esempio ulimit -s 16384.

Ecco un collegamento con le dimensioni dello stack predefinite per gcc.

DFS senza ricorsione:

std::stack<Node> dfs;
dfs.push(start);
do {
    Node top = dfs.top();
    if (top is what we are looking for) {
       break;
    }
    dfs.pop();
    for (outgoing nodes from top) {
        dfs.push(outgoing node);
    }
} while (!dfs.empty())

12
E solo per riferimento, un BFS è lo stesso tranne per il fatto che usi un FIFO invece di uno stack.
Steve Jessop

Sì, o nel gergo STL usa uno std :: deque con pop_front / push_back
Andreas Brinck

il tuo DFS con i risultati dello stack sarà diverso dalla versione di ricorsione. In alcuni casi non importa, ma in altri (ad es.
Nell'ordinamento

Sì, il limite predefinito per VS è effettivamente 1 MB. Maggiori informazioni e il modo per impostare un valore diverso possono essere trovati nella documentazione Microsoft: msdn.microsoft.com/en-us/library/tdkhxaks(v=vs.140).aspx
FrankS101

Preferisco utilizzare una struttura di dati dello stack esplicita per tali algoritmi, piuttosto che la ricorsione, in modo che 1. non dipenda dalla dimensione dello stack di sistema, 2.posso cambiare l'algoritmo per utilizzare una struttura dati diversa, ad esempio coda o coda prioritaria senza lanciare fuori tutto il codice.
Sam Watkins

47

gli stack per i thread sono spesso più piccoli. È possibile modificare l'impostazione predefinita al momento del collegamento o modificare anche in fase di esecuzione. Per riferimento alcuni valori predefiniti sono:

  • glibc i386, x86_64 7,4 MB
  • Tru64 5.1 5,2 MB
  • Cygwin 1.8 MB
  • Solaris 7..10 1 MB
  • MacOS X 10.5 460 KB
  • AIX 5 98 KB
  • OpenBSD 4.0 64 KB
  • HP-UX 11 16 KB

14
Determinati empiricamente da Bruno Haible lists.gnu.org/archive/html/bug-coreutils/2009-10/msg00262.html
pixelbeat

17

Dipendente dalla piattaforma, dipendente dalla toolchain, dipendente da ulimit, dipendente da parametri ... Non è affatto specificato e ci sono molte proprietà statiche e dinamiche che possono influenzarlo.


4
Non ci sono "limiti generali". Su Windows, con le opzioni del linker VC ++ predefinite e il comportamento CreateThread predefinito, in genere circa 1 MiB per thread. Su Linux, con un utente illimitato, credo che in genere non ci siano limiti (lo stack può semplicemente crescere verso il basso per occupare quasi l'intero spazio degli indirizzi). Fondamentalmente, se devi chiedere, non dovresti usare lo stack.
DrPizza

1
Sui sistemi integrati, potresti avere 4k o meno. In tal caso devi chiedere anche quando è ragionevole usare lo stack. La risposta è solitamente un'alzata di spalle gallica.
Steve Jessop

1
Ah vero, spesso accade anche in modalità kernel.
DrPizza

6

Sì, esiste la possibilità di overflow dello stack. Gli standard C e C ++ non impongono cose come la profondità dello stack, questi sono generalmente un problema ambientale.

La maggior parte degli ambienti di sviluppo e / o dei sistemi operativi decenti ti permetteranno di adattare la dimensione dello stack di un processo, al collegamento o al caricamento.

È necessario specificare quale sistema operativo e ambiente di sviluppo si sta utilizzando per un'assistenza più mirata.

Ad esempio, in Ubuntu Karmic Koala, l'impostazione predefinita per gcc è 2M riservato e 4K impegnato, ma questo può essere modificato quando si collega il programma. Usa l' --stackopzione di ldper farlo.


2
@lex: non ci sono limiti generali. Dipende da molti parametri.
Michael Foukarakis

@paxdiablo: qual è il significato di riservato e impegnato?
avd

2
Riservato è la quantità di spazio degli indirizzi da allocare, impegnata è la quantità a cui allegare lo storage di supporto. In altre parole, riservare lo spazio degli indirizzi non significa che la memoria sarà presente quando ne avrai bisogno. Se non usi mai più dello stack 4K, non sprechi memoria reale per gli altri 1.6M. Se vuoi garantire che ci sarà abbastanza stack, riservato e confermato dovrebbero essere identici.
paxdiablo

2
@paxdiablo 2M - 4k non è 1,6M. Sto solo dicendo. (mi ha confuso le prime 3 volte che ho letto il tuo commento)
griffin

2
@griffin, complimenti per la prima persona che l'ha scoperto in 3+ anni. Ovviamente intendevo "resto"
eviterò

5

Ho appena esaurito lo stack al lavoro, era un database e stava eseguendo alcuni thread, in pratica lo sviluppatore precedente aveva lanciato un grande array sullo stack e lo stack era comunque basso. Il software è stato compilato utilizzando Microsoft Visual Studio 2015.

Anche se il thread aveva esaurito lo stack, non è riuscito silenziosamente e ha continuato, lo stack è andato in overflow solo quando è arrivato il momento di accedere ai contenuti dei dati sullo stack.

Il miglior consiglio che posso dare è di non dichiarare array nello stack, specialmente nelle applicazioni complesse e in particolare nei thread, usa invece l'heap. Ecco a cosa serve;)

Inoltre, tieni presente che potrebbe non fallire immediatamente quando si dichiara lo stack, ma solo all'accesso. La mia ipotesi è che il compilatore dichiari lo stack sotto Windows "ottimisticamente", cioè presumerà che lo stack sia stato dichiarato e sia sufficientemente dimensionato fino a quando non arriva ad usarlo e poi scopre che lo stack non è lì.

Sistemi operativi diversi possono avere criteri di dichiarazione dello stack diversi. Si prega di lasciare un commento se si sa quali sono queste politiche.


3

Non sono sicuro di cosa intendi facendo una prima ricerca in profondità su un array rettangolare, ma presumo che tu sappia cosa stai facendo.

Se il limite dello stack è un problema, dovresti essere in grado di convertire la tua soluzione ricorsiva in una soluzione iterativa che inserisce valori intermedi su uno stack allocato dall'heap.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.