Cómo verificar el tamaño del montón para un proceso en Linux

Estaba escribiendo un código y siguió fallando. Más tarde, después de cavar los vertederos, me di cuenta de que estaba sobrepasando el límite máximo de heap (la vida hubiera sido más fácil si hubiera agregado un cheque en malloc). Aunque lo arreglé, ¿hay alguna manera de boost mi tamaño de almacenamiento dynamic?

PD: Una pregunta bastante similar aquí, pero la respuesta no está clara para mí.

El montón generalmente es tan grande como la memoria virtual direccionable en su architecture.

Debería verificar los límites actuales de su sistema con el ulimit -a y buscar el memory size (kbytes, -m) 3008828 máximo de memory size (kbytes, -m) 3008828 esta línea memory size (kbytes, -m) 3008828 , esta línea en mi OpenSuse 11.4 x86_64 con ~ 3.5 GiB de RAM dice que tengo aproximadamente 3GB de RAM por proceso .

Entonces puedes probar tu sistema de verdad con este sencillo progtwig para verificar la memoria máxima utilizable por proceso:

 #include  #include  #include  int main(int argc,char* argv[]){ size_t oneHundredMiB=100*1048576; size_t maxMemMiB=0; void *memPointer = NULL; do{ if(memPointer != NULL){ printf("Max Tested Memory = %zi\n",maxMemMiB); memset(memPointer,0,maxMemMiB); free(memPointer); } maxMemMiB+=oneHundredMiB; memPointer=malloc(maxMemMiB); }while(memPointer != NULL); printf("Max Usable Memory aprox = %zi\n",maxMemMiB-oneHundredMiB); return 0; } 

Este progtwig obtiene memoria en incrementos de 100MiB, presenta la memoria asignada actualmente, asigna 0’s y luego libera la memoria. Cuando el sistema no puede dar más memoria, devuelve NULL y muestra la cantidad máxima utilizable final de RAM.

La advertencia es que su sistema comenzará a intercambiar gran cantidad de memoria en las etapas finales. Dependiendo de la configuración de su sistema, el núcleo puede decidir eliminar algunos procesos. Uso incrementos de 100 MiB para que haya algo de espacio para algunas aplicaciones y el sistema. Deberías cerrar todo lo que no quieras que se cuelgue.

Habiendo dicho eso. En mi sistema donde escribo esto, nada se colgó. Y el progtwig anterior informa apenas lo mismo que ulimit -a . La diferencia es que realmente probó la memoria y por medio de memset() confirmó que la memoria fue dada y utilizada.

Para comparar en una máquina virtual Ubuntu 10.04×86 con 256 MiB de RAM y 400MiB de intercambio, el informe de ulimit fue de memory size (kbytes, -m) unlimited y mi pequeño progtwig informó 524.288.000 bytes, que es aproximadamente la combinación de ram y swap, descontando ram utilizado por otros software y el kernel.

Editar: Como escribió Adam Zalcman, ulimit -m ya no se respeta en los kernels de Linux 2.6 y posteriores, por lo que estoy corregido. Pero ulimit -v es honrado. Para obtener resultados prácticos, debe reemplazar -m por -v, y buscar virtual memory (kbytes, -v) 4515440 . Parece mera casualidad que mi caja de almacenamiento tuviera el valor de “m” coincidiendo con lo que mi pequeña utilidad informaba. Debería recordar que esta es la memoria virtual asignada por el kernel, si el ram físico es insuficiente, se necesitará espacio de intercambio para compensarlo.

Si desea saber la cantidad de memoria RAM física disponible sin perturbar ningún proceso o sistema, puede usar

long total_available_ram =sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE) ;

esto excluirá la memoria caché y la memoria intermedia, por lo que este número puede ser mucho más pequeño que la memoria real disponible. Los cachés del sistema operativo pueden ser bastante grandes y su desalojo puede proporcionar la memoria adicional necesaria, pero eso es manejado por el kernel.

La administración de memoria y montón es un recurso provisto por su biblioteca C (probablemente glibc). Mantiene el montón y le devuelve trozos de memoria cada vez que hace un malloc() . No conoce el límite de tamaño del montón: cada vez que solicita más memoria que la que está disponible en el montón, simplemente va y le pide más al kernel (ya sea usando sbrk() o mmap() ).

Por defecto, kernel casi siempre te dará más memoria cuando te lo pidan. Esto significa que malloc() siempre devolverá una dirección válida. Solo cuando se refiere a una página asignada por primera vez, el kernel realmente se molestará en encontrar una página para usted. Si descubre que no puede entregarle uno, ejecuta un asesino OOM que según cierta medida llamada maldad (que incluye los tamaños de memoria virtual de su proceso y de sus hijos, buen nivel, tiempo de ejecución general, etc.) selecciona una víctima y la envía un SIGTERM . Esta técnica de gestión de la memoria se llama overcommit y es utilizada por el kernel cuando /proc/sys/vm/overcommit_memory es 0 o 1. Consulte la documentación de overcommit-commit en la documentación del kernel para más detalles.

Al escribir 2 en /proc/sys/vm/overcommit_memory , puede desactivar el exceso de compromiso. Si lo hace, el núcleo realmente comprobará si tiene memoria antes de prometerlo. Esto dará como resultado que malloc() devuelva NULL si no hay más memoria disponible.

También puede establecer un límite en la memoria virtual que un proceso puede asignar con setrlimit() y RLIMIT_AS o con el ulimit -v RLIMIT_AS ulimit -v . Independientemente de la configuración de sobrecomisión descrita anteriormente, si el proceso intenta asignar más memoria que el límite, kernel la rechazará y malloc() devolverá NULL. Tenga en cuenta que en el kernel Linux moderno (incluidas las series enteras 2.6.x) el límite en el tamaño residente ( setrlimit() con RLIMIT_RSS o el ulimit -m RLIMIT_RSS ulimit -m ) no es efectivo.

La siguiente sesión se ejecutó en kernel 2.6.32 con 4 GB de RAM y 8GB de intercambio.

 $ cat bigmem.c #include  #include  int main() { int i = 0; for (; i < 13*1024; i++) { void* p = malloc(1024*1024); if (p == NULL) { fprintf(stderr, "malloc() returned NULL on %dth request\n", i); return 1; } } printf("Allocated it all\n"); return 0; } $ cc -o bigmem bigmem.c $ cat /proc/sys/vm/overcommit_memory 0 $ ./bigmem Allocated it all $ sudo bash -c "echo 2 > /proc/sys/vm/overcommit_memory" $ cat /proc/sys/vm/overcommit_memory 2 $ ./bigmem malloc() returned NULL on 8519th request $ sudo bash -c "echo 0 > /proc/sys/vm/overcommit_memory" $ cat /proc/sys/vm/overcommit_memory 0 $ ./bigmem Allocated it all $ ulimit -v $(( 1024*1024 )) $ ./bigmem malloc() returned NULL on 1026th request $ 

En el ejemplo anterior, el intercambio o la eliminación OOM nunca podrían ocurrir, pero esto cambiaría significativamente si el proceso realmente intentara tocar toda la memoria asignada.

Para responder su pregunta directamente: a menos que tenga un límite de memoria virtual establecido explícitamente con el ulimit -v , no hay un límite de tamaño de almacenamiento aparte de los recursos físicos de la máquina o el límite lógico de su espacio de direcciones (relevante en sistemas de 32 bits). Su glibc seguirá asignando memoria en el montón y solicitará más y más desde el kernel a medida que su montón crezca. Eventualmente puede terminar intercambiando mal si toda la memoria física se agota. Una vez que se agote el espacio de intercambio, el asesino OOM del kernel eliminará un proceso aleatorio.

Sin embargo, tenga en cuenta que la asignación de memoria puede fallar por muchas más razones que la falta de memoria libre, fragmentación o alcanzar un límite configurado. Las sbrk() y mmap() utilizadas por el asignador de glib tienen sus propios fallos, por ejemplo, la interrupción del progtwig alcanzó otra dirección ya asignada (por ejemplo, memoria compartida o una página previamente asignada con mmap() ) o el número máximo de asignaciones de memoria del proceso sido excedido

Creo que su problema original fue que malloc no pudo asignar la memoria solicitada en su sistema.

Por qué sucedió esto es específico de tu sistema.

Cuando se carga un proceso, se asigna memoria a una cierta dirección, que es el punto de interrupción del sistema para el proceso. Más allá de esa dirección, la memoria no está mapeada para el proceso. Entonces, cuando el proceso “golpea” el punto de “interrupción” solicita más memoria del sistema y una forma de hacerlo es a través del sistema llamado sbrk
malloc haría eso bajo el capó pero en tu sistema por alguna razón falló.

Puede haber muchas razones para esto, por ejemplo:
1) Creo que en Linux hay un límite para el tamaño máximo de la memoria. Creo que es ulimit y tal vez llegues a eso. Verifica si está establecido en un límite
2) Tal vez tu sistema estaba demasiado cargado
3) Su progtwig realiza una mala gestión de memoria y termina con una memoria fragmentada, por lo que malloc no puede obtener el tamaño de fragmento que ha solicitado.
4) Tu progtwig corrompe las estructuras internas de datos de malloc , es decir, el mal uso del puntero
etc