2010-04-29 12 views
7

En una plataforma integrada (sin partición de intercambio), tengo una aplicación cuyo proceso principal ocupa la mayor parte de la memoria física disponible. El problema es que quiero lanzar un script de shell externo desde mi aplicación, pero usar fork() requiere que haya suficiente memoria para 2x mi proceso original antes de que pueda crearse el proceso hijo (que finalmente se ejecutará en algo mucho más pequeño) .En un proceso que utiliza mucha memoria, ¿cómo puedo generar un shell sin una horquilla ávida de memoria()?

¿Hay alguna forma de invocar un script de shell desde un programa C sin incurrir en la sobrecarga de memoria de un fork()?

He considerado soluciones alternativas como tener un proceso secundario más pequeño que es responsable de crear shells, o tener un script de "observador" que señalo tocando un archivo o algo así, pero preferiría tener algo más simple.

+0

Ver Greg Hewgill a continuación.Esto depende de alguna manera de la plataforma. ¿Podría explicar qué plataforma está utilizando (por ejemplo, ¿tiene una MMU?) – ConcernedOfTunbridgeWells

+0

¿No es una pregunta engañosa * ayer *? http://stackoverflow.com/questions/2731531/faster-forking-of-large-processes-on-linux –

+0

Sí y no, @Pavel, este no es específico de Linux y tiene información adicional sobre lo que se está ejecutando - un script de shell. El otro interlocutor puede haber tenido la opción de volver a escribir su aplicación para usar hilos (si el programa ejecutado era un ejecutable bajo su control en lugar de bash/ksh/other-shell) pero probablemente no en este caso. – paxdiablo

Respuesta

8

Algunas implementaciones de UNIX le darán un vfork (parte de la especificación Single UNIX) que es exactamente como fork, excepto que comparte todas las cosas con el padre.

Con vfork, hay un número muy limitado de cosas que puede hacer en el niño antes de llamar exec para sobrescribir el espacio de direcciones con otro proceso - eso es básicamente lo vfork fue construido para, una versión mínima copia de fork para la fork/exec secuencia.

+0

Gracias, esto es exactamente lo que necesitaba. – kdt

6

Si su sistema tiene una MMU, generalmente se implementa fork() utilizando copy-on-write, que en realidad no asigna más memoria en el momento en que se llama a fork(). Solo se asignaría memoria adicional si escribe en cualquiera de las páginas compartidas con el proceso principal. Un exec() descartaría esas páginas.

Si sabe que no tiene una MMU, entonces quizás fork() efectivamente se implemente utilizando una copia real. Otro enfoque podría ser tener un proceso de ayuda que sea responsable de generar subcapas con las que se comunique utilizando una tubería.

+0

He probado esto en un sistema Linux normal 2.6 que se configuró sin partición de intercambio. Cuando mi proceso principal es de aproximadamente 300 megas, creo que necesito al menos 200 mb de memoria libre como se informa en la parte superior para poder utilizar fork(). Menos y devuelve un error. Creo que el CP solo ocurre si tienes una partición de intercambio que permite a Linux creer que, aunque no tiene que copiar las páginas hasta que escribas, podría hacerlo si lo hicieras. – kdt

+3

Creo que depende de cómo se configure el compromiso excesivo. Linux todavía hace COW, pero cuenta las páginas en contra de la VM disponible, y fallará si el resultado excede la memoria virtual (en caso de que esas páginas se modifiquen posteriormente y necesiten ser copiadas). El intercambio solo permite que el kernel considere que la VM disponible es más grande. – MarkR

-1

Parece que el movimiento prudente en este caso es portar su script de shell (si es posible) a C, y ejecutarlo dentro del proceso; para que no tengas que bifurcar en absoluto.

Luego otra vez; No sé lo que realmente está tratando de hacer do.

-3

En lugar de bifurcar el proceso para generar un caparazón, inicie un caparazón dentro de su proceso (en primer plano) y luego bifurque dentro del caparazón.

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

con el ser/scripts/bgtask:

/bin/ash /scripts/propertask & 

De esta manera se duplica sólo la memoria utilizada por el shell, no por el programa principal. Su programa principal se ocupa durante la duración del desove de los dos shells: original para iniciar bgtask y el clon de fondo iniciado por él, luego la memoria asignada por el primer shell es libre de nuevo.

+1

Creo que puede encontrar que el sistema se implementa como fork/exec/wait, lo que le dará el mismo problema que la pregunta que se intenta resolver. – paxdiablo

+0

paxdiablo es correcto, system() usa fork() internamente. El evento de la página man lo menciona oblicuamente: "... por ejemplo, fork() failed ...": http://linux.die.net/man/3/system – kdt

Cuestiones relacionadas