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.