2008-09-29 18 views
11

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?¿Cómo evitar la fragmentación del montón?

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

EDIT: La aplicación hace algún procesamiento previo con los datos de la imagen, como el reformateo, el cálculo de look-up-mesas, extraer imágenes secundarias de interés ... La aplicación necesita alrededor de 2 GB de RAM durante el proceso, de los cuales aproximadamente 1 , Se pueden usar 5 GB para los datos de imagen.

+0

Creo que probablemente quiera evitar la fragmentación y la desfragmentación. –

+0

Mi apuesta es C++, pero eso es cierto: la pregunta no puede responderse mientras no se conozca el "paradigma" subyacente ... – Georgi

+0

Gracias, Douglas, ¡lo corrigí! –

Respuesta

14

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 le morderá si asigna 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.He aquí un resumen rápido y sucio:

  • Usar una matriz estática de estructuras, cada estructura tiene:
    • Un bloque sólido de la memoria que puede almacenar imágenes N - la CHUNKING ayudará a la fragmentación de control - prueba una inicial N de 5 o así
    • una matriz paralela de Bools que indica si la imagen correspondiente está en uso
  • asignar, buscar la matriz para un búfer vacío y establecer su bandera
    • Si ninguno encontró, añadir una nueva struct al final de la matriz
  • desasignar, encontrar el tampón correspondiente en la matriz (s) y borrar la bandera booleana

Esto 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.

+0

Hola Jeff, ¿alguna vez has estado trabajando en el procesamiento de imágenes médicas? –

+1

Apagado y encendido :) Es posible que desee comprobar vtk o incluso Osirix como material de referencia ... En realidad, la idea anterior es simplemente una forma estándar de manejar la asignación personalizada de tamaño uniforme en C++, aunque ... –

2

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

1

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.

Consulte algunas ideas generales sobre este here.

1

Supongo que está utilizando algo no administrado, porque en las plataformas administradas el sistema (recolector de basura) se encarga 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 y hacemos un seguimiento del montón. fragmentarlo y desfragmentarlo cuando la fragmentación sea grande.

+0

La fragmentación es independiente de la recolección de basura. Ocurre cuando los objetos de larga duración se encuentran diseminados por todo el montón porque su asignación está entremezclada con la de los objetos efímeros. Cómo se deslocaja el material efímero es inmaterial. – dmckee

+0

Las pérdidas de memoria, por supuesto, son otra cuestión. – dmckee

+2

Un buen recolector de basura se ocupará de la fragmentación moviendo objetos y actualizando las referencias. – Constantin

1

Es posible que tenga que implementar la gestió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 la sobrecarga de comunicación entre subprocesos.

5

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

Supongo que Windows XP de 32 bits.

Trate de evitar la necesidad de 100s de MB de memoria contigua, si no tiene suerte, algunos dlls aleatorios se cargarán en puntos incontrastables a través de su espacio de direcciones disponible cortando 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, preasignar 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!

4

Si va a realizar operaciones en una matriz de imagen grande, 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.

2

Lo que llegará 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 solucionar este problema utilizando File Mapping as a memory store; esto se puede hacer de manera que tenga una memoria comprometida y accesible, pero sin utilizar direcciones virtuales en absoluto.

0

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.

Cuestiones relacionadas