In che modo le dimensioni dello stack e dell'heap sono limitate dal sistema operativo?


21

Nota : se è necessario considerare un sistema operativo specifico per poter rispondere, si prega di considerare Linux.

Ogni volta che eseguo un programma, gli verrà dato uno spazio di memoria virtuale per l'esecuzione, con un'area per il suo stack e una per il suo heap.

Domanda 1 : lo stack e l'heap hanno un limite di dimensioni statiche (ad esempio, 2 gigabyte ciascuno), oppure questo limite è dinamico, cambiando in base alle allocazioni di memoria durante l'esecuzione del programma (ovvero, 4 gigabyte in totale da usare da entrambi, quindi se un programma utilizza solo lo stack, sarà in grado di avere uno stack con 4 gigabyte)?

Domanda 2 : come viene definito il limite? È la memoria RAM disponibile totale?

Domanda 3 : Che dire delle sezioni di testo (codice) e dati, come sono limitate?


Risposte:


23

Esistono due diversi limiti di memoria. Il limite di memoria virtuale e il limite di memoria fisica.

Memoria virtuale

La memoria virtuale è limitata dalle dimensioni e dal layout dello spazio degli indirizzi disponibile. Di solito all'inizio sono il codice eseguibile, i dati statici e il passato che fa crescere l'heap, mentre alla fine è l'area riservata dal kernel, prima ancora che le librerie condivise e lo stack (che sulla maggior parte delle piattaforme diminuiscono). Ciò fornisce a heap e stack spazio libero per crescere, mentre le altre aree sono note all'avvio del processo e sono fisse.

La memoria virtuale libera non è inizialmente contrassegnata come utilizzabile, ma è contrassegnata come tale durante l'allocazione. Mentre l'heap può crescere fino a raggiungere tutta la memoria disponibile, la maggior parte dei sistemi non fa crescere automaticamente gli stack. Il limite predefinito di IIRC per lo stack è 8 MiB su Linux e 1 MiB su Windows e può essere modificato su entrambi i sistemi. La memoria virtuale contiene anche qualsiasi file e hardware mappati in memoria.

Uno dei motivi per cui lo stack non può essere sviluppato automaticamente (in modo arbitrario) è che i programmi multi-thread hanno bisogno di uno stack separato per ogni thread, quindi alla fine si ostacolano a vicenda.

Su piattaforme a 32 bit la quantità totale di memoria virtuale è 4GiB, sia Linux che Windows riservano normalmente l'ultimo 1GiB per il kernel, offrendo al massimo 3GiB di spazio di indirizzi. Esiste una versione speciale di Linux che non riserva nulla che ti dà 4GiB completo. È utile per il raro caso di database di grandi dimensioni in cui l'ultimo 1GiB salva la giornata, ma per un uso regolare è leggermente più lento a causa dei ricarichi aggiuntivi della tabella delle pagine.

Su piattaforme a 64 bit la memoria virtuale è 64EiB e non devi pensarci.

Memoria fisica

La memoria fisica viene in genere allocata dal sistema operativo solo quando il processo deve accedervi. Quanta memoria fisica utilizza un processo è un numero molto sfocato, poiché parte della memoria è condivisa tra processi (il codice, le librerie condivise e qualsiasi altro file mappato), i dati dei file vengono caricati in memoria su richiesta e scartati quando c'è carenza di memoria e la memoria "anonima" (quella non supportata dai file) può essere scambiata.

Su Linux cosa succede quando si esaurisce la memoria fisica dipende dalle vm.overcommit_memoryimpostazioni di sistema. L'impostazione predefinita è l'overcommit. Quando chiedi al sistema di allocare memoria, te ne dà alcuni, ma alloca solo la memoria virtuale. Quando accedi effettivamente alla memoria, tenterà di ottenere un po 'di memoria fisica da utilizzare, scartando i dati che possono essere riletti o scambiando le cose se necessario. Se trova che non può liberare nulla, rimuoverà semplicemente il processo dall'esistenza (non c'è modo di reagire, perché quella reazione potrebbe richiedere più memoria e ciò porterebbe a un ciclo infinito).

Ecco come muoiono i processi su Android (che è anche Linux). La logica è stata migliorata con la logica quale processo rimuovere dall'esistenza in base a ciò che il processo sta facendo e all'età. I processi Android semplicemente smettono di fare qualsiasi cosa, ma siedono in background e il "killer della memoria esaurita" li ucciderà quando avrà bisogno di memoria per quelli nuovi.


9

Penso che sia più facile rispondere a questo in base all'ordine di utilizzo della memoria.

Domanda 3: Che dire delle sezioni di testo (codice) e dati, come sono limitate? Testo e dati sono preparati dal compilatore. Il requisito per il compilatore è assicurarsi che siano accessibili e imballarli nella parte inferiore dello spazio degli indirizzi. Lo spazio degli indirizzi accessibili sarà limitato dall'hardware, ad es. Se il registro del puntatore dell'istruzione è a 32 bit, lo spazio degli indirizzi di testo sarebbe 4 GiB.

Domanda 2: come viene definito il limite? È la memoria RAM disponibile totale? Dopo testo e dati, l'area sopra quella è l'heap. Con la memoria virtuale, l'heap può praticamente crescere fino vicino allo spazio massimo indirizzo.

Domanda 1: lo stack e l'heap hanno un limite di dimensioni statiche (ad es. 2 gigabyte ciascuno), oppure questo limite è dinamico, cambiando in base alle allocazioni di memoria durante l'esecuzione del programma (ovvero, 4 gigabyte in totale da usare da entrambi, quindi se un programma utilizza solo lo stack, sarà in grado di avere uno stack con 4 gigabyte)? Il segmento finale nello spazio degli indirizzi di processo è lo stack. Lo stack prende il segmento fine dello spazio indirizzo e comincia dalla fine e cresce verso il basso .

Poiché l'heap cresce e lo stack cresce, sostanzialmente si limitano a vicenda. Inoltre, poiché entrambi i tipi di segmenti sono scrivibili, non è sempre stata una violazione per uno di loro attraversare il confine, quindi è possibile avere buffer o overflow dello stack. Ora ci sono meccanismi per impedire loro di accadere.

C'è un limite prestabilito per heap (stack) per ogni processo con cui iniziare. Questo limite può essere modificato in fase di esecuzione (utilizzando brk () / sbrk ()). Fondamentalmente ciò che accade è quando il processo ha bisogno di più spazio heap e ha esaurito lo spazio allocato, la libreria standard invierà la chiamata al sistema operativo. Il sistema operativo assegnerà una pagina, che di solito sarà gestita dalla libreria utente per l'uso del programma. Vale a dire se il programma vuole 1 KiB, il sistema operativo fornirà 4 KiB aggiuntivi e la libreria darà 1 KiB al programma e ne rimarranno 3 KiB da utilizzare quando il programma ne chiederà altri la prossima volta.

Il più delle volte il layout sarà Testo, Dati, Heap (cresce), spazio non allocato e infine Stack (cresce). Tutti condividono lo stesso spazio degli indirizzi.

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.