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_memory
impostazioni 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.