2010-04-29 2 views
7

Su una piattaforma integrata (senza partizione di swap), ho un'applicazione il cui processo principale occupa la maggior parte della memoria fisica disponibile. Il problema è che voglio lanciare uno script di shell esterno dalla mia applicazione, ma l'uso di fork() richiede che ci sia abbastanza memoria per 2x il mio processo originale prima che il processo figlio (che alla fine eseguirà se stesso in qualcosa di molto più piccolo) possa essere creato .In un processo che utilizza molta memoria, come posso generare una shell senza fork() affamato di memoria?

Quindi esiste un modo per richiamare uno script di shell da un programma C senza incorrere nell'overhead di memoria di un fork()?

Ho considerato soluzioni alternative come avere un processo secondario più piccolo che è responsabile della creazione di shell, o di avere uno script "watcher" che segnali toccando un file o somesuch, ma preferirei avere qualcosa di più semplice.

+0

See Greg Hewgill di seguito.Questo dipende in qualche modo dalla piattaforma: potresti per favore approfondire su quale piattaforma stai utilizzando (ad esempio, ha una MMU?) – ConcernedOfTunbridgeWells

+0

Non è un errore di una domanda? * Ieri * ?? http://stackoverflow.com/questions/2731531/faster-forking-of-large-processes-on-linux –

+0

Sì e no, @Pavel, questo non è specifico per Linux e ha informazioni aggiuntive su ciò che viene eseguito - uno script di shell. L'altro interlocutore potrebbe aver avuto la possibilità di riscrivere la propria applicazione per utilizzare i thread (se il programma di esecuzione era un eseguibile sotto il loro controllo piuttosto che bash/ksh/other-shell) ma probabilmente non in questo caso. – paxdiablo

risposta

8

Alcune implementazioni UNIX forniranno un vfork (parte della specifica UNIX singola) che è esattamente come fork eccetto che condivide tutto il materiale con il genitore.

Con vfork, ci sono un numero molto limitato di cose che potete fare nel bambino prima di chiamare exec per sovrascrivere lo spazio di indirizzamento con un altro processo - che è fondamentalmente ciò che vfork è stato costruito per, una versione copia minima di fork per la fork/exec sequenza.

+0

Grazie, questo è esattamente ciò di cui avevo bisogno. – kdt

6

Se il sistema ha una MMU, di solito viene implementato fork() utilizzando la funzione copy-on-write, che in realtà non assegna più memoria al momento in cui viene chiamato fork(). Memoria aggiuntiva verrà assegnata solo se si si scrive in qualsiasi pagina condivisa con il processo padre. Un exec() eliminerebbe quindi quelle pagine.

Se si sa che non si dispone di una MMU, allora forse fork() viene effettivamente implementato utilizzando una copia effettiva. Un altro approccio potrebbe essere quello di avere un processo di supporto che è responsabile della generazione di subshell, con cui comunichi usando una pipe.

+0

L'ho provato su un normale sistema Linux 2.6 che è stato configurato senza partizione di swap. Quando il mio processo genitore è di circa 300 mega, trovo che ho bisogno di almeno 200 mb di memoria libera come riportato in alto per poter usare fork(). Qualsiasi meno e restituisce un errore. Penso che la COW capiti solo se hai una partizione di swap che permetta a Linux di credere che, sebbene non debba copiare le pagine finché non scrivi, potrebbe farlo se lo facessi. – kdt

+3

Penso che dipenda da come viene configurato l'overcommit. Linux fa ancora COW, ma conta le pagine rispetto alla VM disponibile e fallirà se il risultato supererebbe la memoria virtuale (nel caso in cui tali pagine vengano successivamente modificate e debbano essere copiate). Lo scambio consente solo al kernel di considerare la VM disponibile più grande. – MarkR

-1

Sembra che la mossa prudente in questo caso sia di portare lo script della shell (se possibile) in C, e di eseguirlo all'interno del processo; quindi non devi affatto biforcarti.

Quindi di nuovo; Non so cosa stai effettivamente provando a do.

-3

Invece di eseguire il fork del processo per generare una shell, avviare una shell all'interno del processo (in primo piano) quindi inserirla all'interno della shell.

system("/bin/ash /scripts/bgtask"); 

con l'essere/scripts/bgtask:

/bin/ash /scripts/propertask & 

In questo modo si raddoppia solo la memoria utilizzata dalla shell, non dal programma principale. Il tuo programma principale è occupato per la durata della generazione delle due shell: originale per avviare bgtask e il clone di sfondo lanciato da esso, quindi la memoria allocata dalla prima shell è di nuovo libera.

+1

Penso che potresti scoprire che il sistema è implementato come fork/exec/wait, che ti darà lo stesso problema della domanda cercata per risolvere. – paxdiablo

+0

paxdiablo è corretto, system() utilizza fork() internamente. L'evento della pagina man lo menziona in modo obliquo: "... ad esempio fork() fallito ...": http://linux.die.net/man/3/system – kdt