2011-12-14 19 views
10

¿Copia todo el binario a la memoria antes de que se ejecute? Estoy interesado en esta pregunta y quiero cambiarla de alguna otra manera. Quiero decir, si el binario es 100M grande (parece imposible), podría ejecutarlo mientras lo estoy copiando en la memoria. ¿Podría ser eso posible?Cuando se ejecuta un archivo binario, ¿copia sus datos binarios completos en la memoria a la vez? ¿Podría cambiar eso?

¿O podría decirme cómo ver cómo funciona? ¿Qué herramientas necesito?

+3

El OS normalmente trata esto de una manera sensata. –

+1

100MB ¿binario imposible? Tengo aquí un binario de 6MB compilado a partir de un único programa de 500 CLO, fuertemente estructurado y potenciado en C++. Apuesto a que podría subir eso a 100MB sin demasiados problemas. –

+3

¡Nada es imposible! Simplemente póngase en contacto con un feliz desarrollador de Eclipse, ellos le enseñarán todos los trucos. – Lundin

Respuesta

24

El modelo teórico para un programador de nivel de aplicación hace que parezca que esto es así. En realidad, el proceso de inicio normal (al menos en 1.x Linux, creo 2.xy 3.x están optimizados pero similar) es:

  • El kernel crea un contexto de proceso (más o -menos, máquina virtual)
  • en ese contexto proceso, se define un mapeo de memoria virtual que se asigna de direcciones de memoria RAM para el inicio de su archivo ejecutable
  • Suponiendo que usted está vinculada de forma dinámica (por defecto/habitual), el programa ld.so (por ejemplo, /lib/ld-linux.so.2) definido en los encabezados de su programa configura la asignación de memoria para las bibliotecas compartidas
  • El kernel hace un jmp en la rutina de inicio de su programa (para un programa C, algo así como crtprec80, que llama al main). Como solo ha configurado la asignación y no ha cargado ninguna página (*), esto causa una falla de página de la Unidad de administración de memoria de la CPU, que es una interrupción (excepción, señal) para el kernel.
  • El controlador de fallas de página del kernel carga alguna sección de su programa, incluida la parte que causó el error de página, en la memoria RAM.
  • Como su programa se ejecuta, si accede a una dirección virtual que no tiene RAM de respaldo en este momento, se producirán fallas de página y hará que el núcleo suspenda brevemente el programa , cargue la página del disco y luego devolver el control al programa.Todo esto ocurre "entre instrucciones" y normalmente no se puede detectar.
  • Al usar malloc/new, el kernel crea páginas de lectura y escritura de RAM (sin archivos de respaldo de disco) y las agrega a su espacio de direcciones virtuales.
  • Si lanza un error de página al intentar acceder a una ubicación de memoria que no está configurada en las asignaciones de memoria virtual, obtiene una Señal de violación de segmentación (SIGSEGV), que normalmente es fatal.
  • A medida que el sistema se queda sin RAM física, las páginas de RAM se eliminan; si son copias de solo lectura de algo que ya está en el disco (como un ejecutable o un archivo de objeto compartido), simplemente se desasignan y se vuelven a cargar desde su origen; si son de lectura-escritura (como la memoria que "creó" usando malloc), se escriben en el (archivo de página = archivo de intercambio = partición de intercambio = memoria virtual en disco). El acceso a estas páginas "liberadas" causa otra falla de página y se vuelven a cargar.

Generalmente, hasta que su proceso sea más grande que la RAM disponible -y los datos son casi siempre significativamente más grandes que el ejecutable- puede pretender que está solo en el mundo y ninguno de estos buscapersonas es sucediendo.

Entonces, efectivamente, el kernel es que ejecuta su programa mientras se está cargando (y puede que nunca cargue algunas páginas, si nunca se lanza a ese código/se refieren a esos datos).

Si su inicio es particularmente lento, puede mirar el sistema prelink para optimizar las cargas compartidas de la biblioteca. Esto reduce la cantidad de trabajo que ld.so tiene que hacer al inicio (entre el exec de su programa y el main recibiendo llamadas, así como cuando llama por primera vez a las rutinas de la biblioteca).

En ocasiones, enlazar estáticamente puede mejorar el rendimiento de un programa, pero con un gasto importante de RAM: dado que sus bibliotecas no se comparten, está duplicando "su libc" además del libc compartido que cada otro programa usando, por ejemplo. En general, esto solo es útil en sistemas integrados en los que su programa se ejecuta más o menos solo en la máquina.

(*) En realidad, el núcleo es un poco más inteligente, y por lo general se precarga algunas páginas para reducir el número de fallos de página, pero la teoría es la misma, independientemente de las optimizaciones

+0

Tengo la sensación de que se olvidó del reubicador que necesita pasar por encima de un bloque ejecutable cargado en la memoria (http://en.wikipedia.org/wiki/Relocation_%28computer_science%29). Hasta donde sé, esto sucede una vez durante la carga del código y no estoy seguro de si el controlador 'page-fault' simplemente ejecutará este algoritmo 'relocator' mientras el programa ya se está ejecutando. Entonces, en mi opinión, un bloque ejecutable al menos tiene que cargarse una vez antes de que comience la ejecución. Pero no soy un experto en 'linux-loader' ... – LittleFunnyMan

+2

I * believe * eso es manejado por 'ld.so' en Linux, pero no tiendo a inmiscuirme en los asuntos de los asistentes :-) ... También hay mucha magia negra involucrada en las operaciones' thunk' y tal, eso sucede la primera vez que se invoca una rutina de la biblioteca ... – BRFennPocock

+0

Consulte http://em386.blogspot.com/2006/10/resolving-elf-relocation-name-symbols.html para obtener una explicación sobre cómo funciona la reubicación. –

6

No, solo carga las páginas necesarias en la memoria. Esto es paginación por demanda.

No conozco una herramienta que realmente pueda mostrar eso en tiempo real, pero puede echar un vistazo a /proc/xxx/maps, donde xxx es el PID de su proceso.

+0

En Gnome, el Monitor del sistema mostrará los mapas de memoria. Aplicaciones/Herramientas del sistema/Monitor del sistema → Pestaña Procesos → haga clic derecho en proceso → Mapas de memoria. La ventana a menudo aparece vacía cuando se abre, porque las barras de desplazamiento están colocadas torpemente, así que revíselas si cree que tiene una pantalla en blanco :-) – BRFennPocock

2

Mientras hace una pregunta válida, no creo que sea algo de lo que deba preocuparse. Primero, un binario de 100M no es imposible. En segundo lugar, el cargador del sistema cargará en la memoria las páginas que necesita desde ELF (formato ejecutable y enlazable), y realizará varias reubicaciones, etc., que lo harán funcionar, si es necesario. También cargará todas sus dependencias de bibliotecas compartidas necesarias de la misma manera. Sin embargo, este no es un proceso increíblemente lento, y que realmente no necesita ser optimizado. Podría decirse que cualquier "optimización" tendría una sobrecarga significativa para asegurarse de que no está tratando de usar algo que no se ha cargado en su debido momento, y posiblemente sería menos eficiente.

Si tiene curiosidad por lo que se asigna, como dice fge, puede consultar/proc/pid/maps. Si desea ver cómo un programa se carga, puede intentar ejecutar un programa con strace, como:

strace ls 

Es bastante detallado, pero debe darle una idea de la mmap() llama, etc.

Cuestiones relacionadas