que diferencia performance memory-management heap fragmentation

performance - diferencia - ¿Cómo evitar la fragmentación del montón?



malloc c (9)

Actualmente estoy trabajando en un proyecto para el procesamiento de imágenes médicas, que necesita una gran cantidad de memoria. ¿Hay algo que pueda hacer para evitar la fragmentación del montón y acelerar el acceso a los datos de imagen que ya se han cargado en la memoria?

La aplicación se ha escrito en C ++ y se ejecuta en Windows XP.

EDITAR: la aplicación realiza un preproceso con los datos de imagen, como reformatear, calcular tablas de búsqueda, extraer imágenes secundarias de interés ... La aplicación necesita aproximadamente 2 GB de RAM durante el procesamiento, de los cuales se pueden usar aproximadamente 1,5 GB. para los datos de imagen.


Adivinando aquí que quería decir evitar la fragmentación y no evitar la desfragmentación . También adivinando que está trabajando con un lenguaje no administrado (c o C ++ probablemente). Sugeriría que asigne grandes porciones de memoria y luego sirva asignaciones de pila de los bloques de memoria asignados. Este grupo de memoria porque contiene grandes bloques de memoria es menos propenso a la fragmentación. En resumen, debe implementar un asignador de memoria personalizado.

Vea algunas ideas generales sobre esto aquí .


Es posible que necesite implementar la administración de memoria manual. ¿Los datos de imagen son de larga duración? De lo contrario, puede usar el patrón utilizado por el servidor web de apache: asigne grandes cantidades de memoria y envuélvalas en grupos de memoria. Pase esos grupos como el último argumento en funciones, para que puedan usar el conjunto para satisfacer la necesidad de asignar memoria temporal. Una vez que la cadena de llamadas finaliza, ya no se debe usar toda la memoria del conjunto, por lo que puede restregar el área de memoria y volver a utilizarla. Las asignaciones son rápidas, ya que solo significan agregar un valor a un puntero. La desasignación es realmente rápida, ya que liberará bloques de memoria muy grandes a la vez.

Si su aplicación es multiproceso, es posible que necesite almacenar el grupo en el almacenamiento local de subprocesos, para evitar gastos indirectos de comunicación cruzada.


Hay respuestas, pero es difícil ser general sin conocer los detalles del problema.

Supongo que Windows XP de 32 bits.

Intente evitar la necesidad de cientos de MB de memoria contigua; si tiene mala suerte, algunas dlls aleatorias se cargarán en puntos incontrovables a través de su espacio de direcciones disponible reduciendo rápidamente áreas muy grandes de memoria contigua. Dependiendo de las API que necesite, esto puede ser bastante difícil de prevenir. Puede ser bastante sorprendente cómo la asignación de un par de bloques de memoria de 400 MB, además de un uso de memoria "normal", puede dejarlo sin lugar para asignar un bloque "pequeño" final de 40 MB.

Por otro lado, preasigna porciones de tamaño razonable a la vez. Del orden de 10 MB más o menos es un buen tamaño de bloque de compromiso. Si puede organizar la partición de sus datos en este tipo de fragmentos de tamaño, podrá llenar el espacio de direcciones de forma razonablemente eficiente.

Si aún se va a quedar sin espacio de direcciones, necesitará poder ingresar y sacar bloques de página en función de algún tipo de algoritmo de almacenamiento en caché. Elegir los bloques correctos para enviar la página va a depender mucho de su algoritmo de procesamiento y necesitará un análisis cuidadoso.

Elegir dónde colocar las cosas es otra decisión. Puede decidir simplemente escribirlos en archivos temporales. También podría investigar la API Extensiones de ventanas de direcciones de Microsoft. En cualquier caso, debe tener cuidado en el diseño de su aplicación para limpiar los punteros que apuntan a algo que está a punto de ser localizado, de lo contrario, cosas realmente malas (tm) sucederán.

¡Buena suerte!


Si está procesando imágenes médicas, es probable que esté asignando bloques grandes a la vez (512x512 imágenes de 2 bytes por píxel). La fragmentación te morderá si asignas objetos más pequeños entre las asignaciones de los almacenamientos intermedios de imágenes.

Escribir un asignador personalizado no es necesariamente difícil para este caso de uso en particular. Puede usar el asignador estándar de C ++ para su objeto Imagen, pero para el búfer de píxeles puede usar la asignación personalizada que se gestiona en su objeto Imagen. Aquí hay un resumen rápido y sucio:

  • Usa una matriz estática de estructuras, cada estructura tiene:
    • Un pedazo sólido de memoria que puede contener N imágenes - la fragmentación ayudará a controlar la fragmentación - pruebe una N inicial de 5 o más
    • Una matriz paralela de bools que indica si la imagen correspondiente está en uso
  • Para asignar, busca en la matriz un búfer vacío y establece su bandera
    • Si no se encuentra ninguno, agregue una nueva estructura al final de la matriz
  • Para desasignar, encuentre el búfer correspondiente en la (s) matriz (es) y borre la bandera booleana

Esta es solo una idea simple con mucho espacio para la variación. El truco principal es evitar liberar y reasignar los búferes de píxeles de la imagen.


Si va a realizar operaciones en una matriz de imágenes de gran tamaño, es posible que desee considerar una técnica llamada "mosaico". La idea general es cargar la imagen en la memoria para que el mismo bloque contiguo de bytes no contenga píxeles en una línea, sino más bien un cuadrado en el espacio 2D. La razón detrás de esto es que realizaría más operaciones que están más cerca entre sí en 2D que en una línea de escaneo.

Esto no reducirá el uso de memoria, pero puede tener un gran impacto en el intercambio de páginas y el rendimiento.


Sin mucha más información sobre el problema (por ejemplo, el idioma), una cosa que puede hacer es evitar la distribución de la asignación mediante la reutilización de asignaciones y no asignar, operar y liberar. El localizador como dlmalloc maneja la fragmentación mejor que Win32 montones.


Supongo que estás utilizando algo no administrado, porque en las plataformas administradas el sistema (recolector de basura) se ocupa de la fragmentación.

Para C / C ++ puede usar algún otro asignador, que el predeterminado. (Por lo general, había algunos hilos sobre los asignadores en el flujo de luz).

Además, puede crear su propio almacenamiento de datos. Por ejemplo, en el proyecto en el que estoy trabajando actualmente, tenemos un almacenamiento (pool) personalizado para mapas de bits (los almacenamos en una gran cantidad de memoria contigua), porque tenemos muchos de ellos, y hacemos un seguimiento del montón fragmentarlo y desfragmentarlo cuando la fragmentación sea grande.


Lo que tocará aquí es el límite del rango de direcciones virtuales, que con 32b Windows le ofrece como máximo 2 GB. También debe tener en cuenta que el uso de una API gráfica como DirectX u OpenGL utilizará porciones extensas de esos 2 GB para frame buffer, texturas y datos similares.

1.5-2 GB para una aplicación 32b es bastante difícil de lograr. La forma más elegante de hacerlo es usar la aplicación 64b OS y 64b. Incluso con la aplicación 64b OS y 32b esto puede ser algo viable, siempre y cuando use LARGE_ADDRESS_AWARE .

Sin embargo, como necesita almacenar datos de imagen, también puede ser capaz de evitar esto utilizando File Mapping como un almacén de memoria : esto se puede hacer de tal manera que tenga una memoria comprometida y accesible, pero sin utilizar ningún virtual direcciones en absoluto.


Si puede aislar exactamente aquellos lugares donde es probable que asigne bloques grandes, puede (en Windows) llamar directamente a VirtualAlloc en lugar de pasar por el administrador de memoria. Esto evitará la fragmentación dentro del administrador de memoria normal.

Esta es una solución fácil y no requiere el uso de un administrador de memoria personalizado.