Fork () copia immediatamente l'intero heap del processo in Linux?


30

Una fork()chiamata di sistema clona un processo figlio dal processo in esecuzione. I due processi sono identici ad eccezione del loro PID.

Naturalmente, se i processi stanno solo leggendo dai loro cumuli piuttosto che scrivere su di esso, copiare l'heap sarebbe un enorme spreco di memoria.

Viene copiato l'intero heap del processo? È ottimizzato in un modo che solo la scrittura innesca una copia heap?

Risposte:


19

La totalità di fork()è implementato utilizzando mmap / copy-on-write.

Ciò non riguarda solo l'heap, ma anche librerie condivise, stack, aree BSS.

Il che, per inciso, significa che fork è un'operazione estremamente leggera, fino a quando i 2 processi risultanti (padre e figlio) iniziano effettivamente a scrivere su intervalli di memoria. Questa funzione contribuisce in modo determinante alla letalità delle bombe a forcella: si finisce con troppi processi prima che il kernel venga sovraccaricato con la replica e la differenziazione delle pagine.

Ti verrà difficile trovare in un sistema operativo moderno un esempio di un'operazione in cui il kernel esegue una copia cartacea (i driver di dispositivo sono l'eccezione): è molto, molto più semplice ed efficiente impiegare la funzionalità VM.

Even execve()è essenzialmente "per favore mmap il binario / ld.so / whatnot, seguito da execute" - e la VM gestisce l'effettivo caricamento del processo su RAM ed esecuzione. Le variabili locali non inizializzate finiscono per essere mmapate da una "pagina zero" - speciale pagina di sola lettura copia-scrittura contenente zero, le variabili locali inizializzate finiscono per essere mmapate (copia-su-scrittura, di nuovo) dal file binario stesso, eccetera.


Una notevole eccezione sono i processi Java. Cerca "fork java memory" e troverai dozzine di problemi che interessano JVM di server di grandi dimensioni o JVM incorporata che provano a eseguire un comando shell piccolo e si bloccano miseramente in un'eccezione "Impossibile allocare memoria" (questi sono solo collegamenti casuali, questo problema è sistemico agli ambienti Java). Questa risposta SO accusa il garbage collector e il compilatore JIT di JVM di non condividere la memoria dei processi.
WhiteWinterWolf

24

Il kernel Linux implementa Copy-on-Write quando fork()viene chiamato. Quando viene eseguita la syscall, le pagine che padre e figlio condividono sono contrassegnate come di sola lettura.

Se una scrittura viene eseguita nella pagina di sola lettura, viene quindi copiata, poiché la memoria non è più identica tra i due processi. Pertanto, se vengono eseguite solo operazioni di lettura, le pagine non verranno affatto copiate.


1
+1 Grazie! 1. Potresti fornire link di riferimento? 2. L'heap è stato copiato interamente o in parte?
Adam Matan,

4
2. - Nelle pagine :) Il kernel ha ben poca comprensione di cosa sia "heap" - per il kernel, è solo un mucchio di pagine private mmapped, che gli allocatori di libc gestiscono come vuole.
qdot

È davvero una bomba a forca necessariamente? Mi sembra che invece di biforcare il processo corrente, questo codice creerà più istanze dello stesso programma che si eseguono dall'inizio anziché dalla successiva istruzione dopo la fork()chiamata.
Sherrellbc,

@mmk FYI, sono rimasto piuttosto sorpreso dalla tua "Nota interessante:" e quindi ho testato (su Linux 3.2.0) per vedere, e non sembra essere vero. Ho usato /proc/self/pagemapper determinare l'indirizzo virtuale per la mappatura della pagina fisica ai fini del test. Come mi aspettavo, se il nipote e solo il nipote scrivono la pagina condivisa, allora il genitore e il figlio originale continuano a condividerla. Solo il nipote finisce con una copia privata.
Celada,

@Celada. Hmm. L'avevo letto da qualche parte e non ricordo la versione del kernel a cui si riferiva (probabilmente una versione precedente?), Quindi potrebbe non essere più valida.
mmk

10

Linux esegue Copy-on-Write. Quando viene forkcreato un nuovo processo, le pagine allocate vengono contrassegnate come di sola lettura e condivise tra padre e figlio. Quando uno di essi tenta di modificare una pagina, viene generato un errore di pagina che comporta la copia della pagina e la regolazione appropriata della tabella delle pagine.

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.