En Linux, ¿cómo se determina el tamaño del montón asignado para un programa?

Creo que la respuesta de Travis combina el espacio de direcciones con la asignación.
Los procesos de Linux son casi todos descendientes de init, que generalmente es de 250-300KB RSS y aproximadamente 2.5MB VSIZE. El tamaño inicial de cualquier proceso se hereda de su padre a través de fork () (técnicamente un contenedor alrededor de clone () en Linux).

La mayoría de esas páginas clonadas (editables) son CoW (copia en escritura) tanto para padres como para hijos … también hay muchas asignaciones de memoria, muchas de las cuales son de solo lectura (bibliotecas compartidas … archivos .so … en su mayoría). También puede haber algunas asignaciones de memoria compartibles y grabables que incluso pueden ser en forma de IPC anónimo (es decir, mmap () sin ningún archivo real en ningún almacén de respaldo).

Escribir páginas de CoW desencadena asignaciones (manejadas por el kernel como parte de la falla de la página. He leído, en el pasado distante, que la mayoría (¿todas?) De las asignaciones de espacio de usuario en Linux comienzan como referencias a una sola página “cero” de CoW (que consta de todos los caracteres ASCII NUL). Las fallas de página se “copian” en cualquier página libre (que también está en blanco … un flujo de NUL ASCII).

Un execve () provoca desencadena una serie de asignaciones de memoria (el nuevo, generalmente binario ELF, y todos sus archivos de objetos compartidos .so , por ejemplo).

Lo que no sé es precisamente cuando la memoria se * libera * en las circunstancias que rodean un par de llamadas al sistema fork () / execve () . Puede ser realizado por el núcleo como parte del manejo de execve () , o puede ser realizado por el código de tiempo de ejecución C ( libcrt.so .0 ) … tal vez un brk () o sbrk () y quizás basado en algunos de los binarios Encabezados ELF?

Supongo que puede leer las fuentes de Linux para la llamada al sistema execve () y las fuentes de GNU libc para libcrt para conocer los detalles.

Aquí hay una página que parece tener una gran cantidad de información sobre el diseño de la memoria del proceso de Linux: Anatomía de un programa en memoria que forma parte de toda una serie de artículos relacionados. No parece responder a su pregunta directamente, pero creo que el fondo será útil; como lo harán algunos de los otros en esa serie. El otro que recomendaría, en esa serie es: Caché de página, el asunto entre memoria y archivos.

Cuando los haya leído, creo que verá que su pregunta es difícil de responder. La inicialización del programa como proceso es bastante compleja.

También vale la pena señalar que un programa, en Linux, podría estar vinculado a cualquiera de los diferentes administradores de asignación de memoria que no sea el que está integrado en GNU libc (ptmalloc de Wolfram Gloger) Por ejemplo, está TCMalloc: Malloc de almacenamiento en caché de subprocesos y jemalloc. Algunos programadores de C incluso prefieren escribir su propio administrador de almacenamiento dinámico.

No sé si vincularlos tendría algún efecto significativo sobre el tamaño inicial del montón (lo que interpreto que significa en el momento en que se llama al main () de un programa. Creo que los distintos montón los administradores solo afectarían el montón a medida que se ejecuta el programa (y asigna dinámicamente espacio en el montón).

El montón generalmente es tan grande como la memoria virtual direccionable en su arquitectura. Supongamos que se trata de un proceso de Java, por lo general, debe especificar un tamaño de almacenamiento dinámico si necesita una gran cantidad de datos en el almacenamiento dinámico, pero esto tiene que ver con JVM y no con su sistema operativo.

El montón no suele estar limitado, por lo tanto, es parte de la razón por la que se usa. Su sistema operativo asigna su pila, sin embargo, el montón normalmente no se puede expandir para usar la totalidad de la memoria de su sistema a menos que se especifique lo contrario (consulte ulimit).