Solución:
entonces, ¿por qué malloc llama a mmap cuando se trata de asignar un gran tamaño de memoria?
La respuesta corta es para mejorar la eficiencia en implementaciones más recientes de Linux y los algoritmos de asignación de memoria actualizados que vienen con ellos. Pero tenga en cuenta que este es un tema que depende mucho de la implementación, y los porqués y los por qué variarían mucho para las diferentes cosechas y sabores del sistema operativo Linux específico que se está discutiendo.
Aquí hay un artículo bastante reciente sobre las partes de bajo nivel. mmap()
y brk()
jugar en la asignación de memoria de Linux. Y, un artículo de Linux Journal no tan reciente, pero aún relevante, que incluye contenido que es muy específico para el tema aquí, incluido esto:
Para solicitudes muy grandes, malloc () usa la llamada al sistema mmap () para encontrar espacio de memoria direccionable. Este proceso ayuda a reducir los efectos negativos de la fragmentación de la memoria. cuando se liberan grandes bloques de memoria pero bloqueados por bloques más pequeños y asignados más recientemente que se encuentran entre ellos y el final del espacio asignado. En este caso, de hecho, si el bloque se hubiera asignado con brk (), el sistema habría quedado inutilizable incluso si el proceso lo hubiera liberado.
(énfasis mío)
Con respecto a brk()
:
por cierto, “…mmap () no existía en las primeras versiones de Unix. brk()
era la única forma de aumentar el tamaño del segmento de datos del proceso en ese momento. La primera versión de Unix con mmap () fue SunOS a mediados de los 80, la primera versión de código abierto fue BSD-Reno en 1990.“. Desde entonces, la implementación moderna de algoritmos de asignación de memoria se ha refactorizado con muchas mejoras, lo que reduce en gran medida la necesidad de que incluyan el uso de brk()
.
mmap
(cuando se usa con MAP_ANONYMOUS
) asigna una porción de RAM que se puede colocar en cualquier lugar dentro del espacio de direcciones virtuales del proceso, y que se puede desasignar más tarde (con munmap
) independientemente de todas las demás asignaciones.
brk
cambia la dirección final de una única “arena” contigua del espacio de direcciones virtuales: si esta dirección se aumenta, asigna más memoria a la arena, y si se reduce, desasigna la memoria al final de la arena. Por lo tanto, la memoria asignada con brk
solo se puede devolver al sistema operativo cuando un rango continuo de direcciones al final de la arena ya no es necesario para el proceso.
Utilizando brk
para pequeñas asignaciones, y mmap
para asignaciones grandes, es una heurística basada en el supuesto de que es más probable que las asignaciones pequeñas tengan la misma vida útil, mientras que es más probable que las asignaciones grandes tengan una vida útil que no esté correlacionada con la vida útil de otras asignaciones. Entonces, las asignaciones grandes usan la primitiva del sistema que les permite ser desasignados independientemente de cualquier otra cosa, y las asignaciones pequeñas usan la primitiva que no lo hace.
Esta heurística no es muy confiable. La actual generación de malloc
implementaciones, si mal no recuerdo, se ha rendido por completo en brk
y usos mmap
para todo. los malloc
La implementación que sospecho que está viendo (la de la Biblioteca GNU C, basada en sus etiquetas) es muy antigua y continúa usándose principalmente porque nadie es lo suficientemente valiente como para correr el riesgo de cambiarla por algo más nuevo que probablemente pero no ciertamente ser mejor.