A cosa serve la pila?
Ogni programma è costituito da funzioni/subroutine/qualunque sia la lingua desiderata. Quasi sempre, queste funzioni hanno uno stato locale. Anche in un ciclo semplice, hai bisogno di un punto per tenere traccia del contatore del ciclo, giusto? Questo deve essere memorizzato da qualche parte.
Il problema delle funzioni è che l'altra cosa che fanno quasi sempre è chiamare altre funzioni. Queste altre funzioni hanno il loro stato locale - le loro variabili locali. Non vuoi che le tue variabili locali interferiscano con i locali del tuo chiamante. L'altra cosa che deve succedere è, quando FunctionA chiama FunctionB e quindi deve fare qualcos'altro, vuoi che le variabili locali in FunctionA siano ancora lì, e abbiano i loro stessi valori, quando FunctionB è fatto.
Tenere traccia di queste variabili locali è a cosa serve lo stack. Ogni chiamata di funzione viene eseguita impostando quello che viene chiamato un stack frame. Il frame dello stack include in genere l'indirizzo di ritorno del chiamante (per quando la funzione è terminata), i valori per qualsiasi parametro del metodo e l'archiviazione per qualsiasi variabile locale.
Quando viene chiamata una seconda funzione, viene creato un nuovo frame di stack, inserito nella parte superiore della pila e la chiamata viene eseguita. La nuova funzione può funzionare felicemente sul suo stack frame. Quando la seconda funzione ritorna, il suo stack frame viene fatto scoppiare (rimosso dalla pila) e il frame del chiamante è di nuovo posizionato come prima.
Quindi questo è lo stack. Allora, qual è il mucchio? Ha un uso simile - un posto dove archiviare i dati. Tuttavia, spesso c'è bisogno di dati che durino più a lungo di un singolo frame dello stack. Non può andare in pila, perché quando la chiamata alla funzione ritorna, il frame dello stack viene ripulito e boom: i dati vengono inviati. Quindi lo metti invece nell'heap. L'heap è un blocco di memoria fondamentalmente non strutturato. Chiedi il numero x di byte, e lo ottieni, e può quindi festeggiare su di esso. In C/C++, la memoria heap rimane allocata finché non viene deallocato esplicitamente. Nei linguaggi raccolti tramite garbage (Java/C#/Python/etc.) La memoria heap verrà liberata quando gli oggetti su di essa non verranno più utilizzati.
per affrontare le questioni specifiche dall'alto:
Qual è la differenza tra un overflow dello stack e un buffer overflow?
Sono entrambi casi di esecuzione su un limite di memoria. Un overflow dello stack è specifico per lo stack; hai scritto il tuo codice (la ricorsione è una causa comune, ma non l'unica) in modo che abbia troppe chiamate di funzioni nidificate, o stai memorizzando un sacco di cose grandi nello stack, e finisce fuori dalla stanza. La maggior parte dei sistemi operativi mette un limite alle dimensioni massime che lo stack può raggiungere e quando si raggiunge quel limite si ottiene lo stack overflow. L'hardware moderno è in grado di rilevare gli overflow dello stack e di solito è fatale per il tuo processo.
Un buffer overflow è leggermente diverso. Quindi prima domanda: cos'è un buffer? Bene, è un pezzo limitato di memoria. Quella memoria potrebbe essere in pila, o potrebbe essere in pila. Ma la cosa importante è che hai X byte che sai di avere accesso. Quindi scrivi del codice che scrive X + più byte in quello spazio. Il compilatore probabilmente ha già usato lo spazio oltre il tuo buffer per altre cose, e scrivendo troppo, hai sovrascritto quelle altre cose. Gli overrun del buffer spesso non si vedono immediatamente, poiché non li noti fino a quando non provi a fare qualcosa con l'altra memoria che è stata cestinata.
Inoltre, ricorda come ho menzionato che anche gli indirizzi di ritorno sono memorizzati nello stack? Questa è la fonte di molti problemi di sicurezza dovuti ai sovraccarichi del buffer. Hai codice che utilizza un buffer nello stack e ha una vulnerabilità di overflow. Un hacker intelligente può strutturare i dati che traboccano il buffer per sovrascrivere quell'indirizzo di ritorno, per puntare al codice nel buffer stesso, ed è così che ottengono il codice da eseguire. È brutto.
Cosa succede quando inizialmente inizializzare le variabili nel codice .. Sono nel segmento di codice o nel segmento di dati o nel mucchio?
Ho intenzione di parlare da una prospettiva C/C++ qui. Supponendo che tu abbia una dichiarazione di variabile:
int i;
Tale riserva (in genere) quattro byte sullo stack. Se invece si ha:
char * buffer = malloc (100);
Questo effettivamente riserva due blocchi di memoria. La chiamata a malloc alloca 100 byte nell'heap. Ma è necessario anche l'archiviazione per il puntatore, il buffer. Quella memoria è, ancora, in pila, e su una macchina a 32 bit sarà 4 byte (la macchina a 64 bit userà 8 byte).
Dove vengono memorizzati gli array ... ???
Dipende da come li si dichiara. Se si esegue un array semplice:
char str [128];
ad esempio, riserva 128 byte nello stack. C non colpisce mai l'heap a meno che non lo si chieda esplicitamente chiamando un metodo di allocazione come malloc.
Se invece si dichiara un puntatore (come il buffer sopra) la memoria per il puntatore è nello stack, i dati effettivi per l'array si trovano nell'heap.
È che dopo che il mio codice viene eseguito tutto ciò che era nel mio mucchio viene cancellato ... ???
Fondamentalmente sì. Il sistema operativo pulirà la memoria utilizzata da un processo dopo la sua uscita. L'heap è un frammento di memoria nel tuo processo, quindi il sistema operativo lo ripulirà. Anche se dipende da cosa intendi con "ripulisci". Il sistema operativo marca quei pezzi di RAM come ora gratuiti, e riutilizzerà in seguito. Se hai codice di pulizia esplicito (come i distruttori C++) dovrai assicurarti che vengano richiamati, il sistema operativo non li chiamerà per te.
Tutto sommato, per favore mi parli di heap in un modo più semplice del solito, è per malloc e alloc?
L'heap è, molto simile al suo nome, un mucchio di byte gratuiti che puoi prendere un pezzo alla volta, fare quello che vuoi, quindi tornare a usare per qualcos'altro. Afferri un pezzo di byte chiamando malloc e lo rinvii chiamando gratis.
Perché dovresti farlo?Beh, ci sono un paio di motivi comuni:
Non sai quanti di una cosa è necessario fino fase di esecuzione (sulla base degli input dell'utente, per esempio). Pertanto, si assegna dinamicamente all'heap come necessario.
Sono necessarie grandi strutture di dati. Su Windows, ad esempio, lo stack di un thread è limitato per impostazione predefinita a 1 meg. Se stai lavorando con grandi bitmap , ad esempio, questo sarà un modo rapido per far saltare lo stack e ottenere un overflow dello stack. Quindi prendi lo spazio dell'heap, che di solito è lo molto più grande dello stack.
Il codice, i dati, lo stack e l'heap?
Non proprio una domanda, ma volevo chiarire. Il segmento "codice" contiene i byte eseguibili per la tua applicazione. In genere i segmenti di codice vengono letti solo in memoria per impedire la manomissione. Il segmento dati contiene costanti che sono compilate nel codice: cose come le stringhe nel codice o gli inizializzatori di array devono essere memorizzati da qualche parte, il segmento di dati è dove vanno. Ancora, il segmento dati è in genere di sola lettura.
Lo stack è una sezione di memoria scrivibile e di solito ha una dimensione limitata. Il sistema operativo inizializzerà lo stack e il codice di avvio C chiamerà la funzione main() per te. L'heap è anche una sezione di memoria scrivibile. È riservato dal sistema operativo e funziona come malloc e gestisce gratuitamente i blocchi e li rimette a posto.
Quindi, questa è la panoramica. Spero che aiuti.
possibile duplicato di [Cosa e dove sono lo stack e l'heap] (http://stackoverflow.com/questions/79923/what-and-where-are-the-stack-and-heap) – Naveen