2010-07-07 22 views
5

Tengo una aplicación escrita usando .NET 3.5 SP1 que descarga imágenes de un sitio externo y las muestra a los usuarios finales. En raras ocasiones, mis usuarios están experimentando errores de OutOfMemory porque están descargando imágenes enormes. Algunas veces, los datos brutos asociados con estas imágenes son grandes, pero más a menudo, las dimensiones de las imágenes son enormes. Me doy cuenta de que nunca podré evitar el hecho de que estos errores OOM se producen para imágenes particulares. Sería MUY útil, sin embargo, si de alguna manera pudiera determinar si cargar una imagen en particular daría lugar a un problema OOM antes de intentar cargar la imagen.Cómo detectar si la carga de una imagen generará una excepción OutOfMemory en .NET?

Los datos de las imágenes se cargan en un Stream y luego la imagen se convierte en System.Drawing.Image haciendo una llamada a System.Drawing.Image.FromStream (stream). No tengo la opción de almacenar estas imágenes en el disco primero. Deben cargarse a través de la memoria.

Si alguien tiene alguna sugerencia o sugerencia que me permita detectar que cargar una imagen daría lugar a una excepción de OOM, lo agradecería mucho.

+0

"Los datos de las imágenes se cargan en una secuencia" ... por arte de magia, ¿o cómo? – Will

+0

@Will - "descarga imágenes de un sitio externo" –

+0

@Joel para que obtenga una secuencia, luego alimenta esa secuencia en un flujo de memoria, y luego utiliza esa secuencia con una imagen? ¿Y se está preguntando por qué se está quedando sin memoria? ¿Por qué no usar el flujo original y cortar al intermediario? ¿Soy el loco? – Will

Respuesta

1

OutOfMemory es una de esas excepciones en las que no tiene muchas opciones buenas. Todo lo que pueda predecir de manera concluyente que va a obtener la excepción probablemente solo genere la excepción.

Diría que su mejor opción es hacer un perfil del comportamiento y crear su propio conjunto de reglas predictivas o simplemente codificar tamaños máximos para su aplicación. No es bonito, pero te llevará hasta allí.

1

lo podría hacer en esta pregunta y ver si ayuda: How do I reliably get an image dimensions in .NET without loading the image?

La idea no sería descargar sólo una parte de la imagen total (la cabecera específicamente) para que pueda leer los metadatos. Luego puede usar la información allí para determinar qué tan grande es la imagen, y negar que se descargue por completo si ve que será demasiado grande.

En el lado negativo, parece que tendría que escribir un método para descomponer el binario de cada tipo de archivo que desea controlar.

+0

Sí, estábamos pensando en usar este enfoque. Nuestra mayor preocupación sigue siendo que no tenemos una buena manera de predecir con exactitud cuánta memoria usará System.Drawing.Image.FromImage. Necesitamos admitir cualquier tipo de imagen que .NET soporte nativamente. Además de necesitar descomponer el binario de cada tipo de archivo soportado por .NET, tendríamos que encontrar un método que prediga con precisión la cantidad de memoria utilizada cuando se cargan esas imágenes. ¡Esto parece algo en lo que un equipo completo de desarrolladores podría estar trabajando durante meses! :( – Keith

1

Tienes un problema con la gallina y el huevo. Para hacer una especie de suposición, necesitas saber el tamaño de la imagen. No sabes el tamaño hasta que lo cargaste.

No es realmente útil de todos modos. Si obtienes OOM realmente depende de cuán fragmentado ha sido el espacio de direcciones de la memoria virtual. Y eso es no fácil de encontrar en Windows. La función API de HeapWalk() es necesaria y esa es una función no saludable para usar. Consulte la letra pequeña en el artículo de la biblioteca de MSDN. Especialmente malo en un programa administrado, no lo use.

Tenga en cuenta que esta excepción OOM no es el mismo tipo de OOM que obtendría cuando utilizara demasiada memoria administrada. En realidad, es una excepción GDI + y puede recuperarse fácilmente de ella. Simplemente tome la excepción y muestre un mensaje "Lo siento, no pude hacerlo".

Si conoce el tamaño del frente de alguna manera, entonces puede asumir con bastante seguridad que el ancho * alto * 4> 550 MB no funcionará en un programa de 32 bits. Este límite baja rápidamente después de funcionar por un tiempo.

1

Si está descargando las imágenes de un sitio externo, y el sitio externo configura el encabezado HTTP Content-Length, es posible que pueda estimar si la imagen encajará en la memoria incluso antes de comenzar a descargarla. .

+0

Obtenemos el encabezado content-length. Sin embargo, el tamaño físico de los datos no es un gran predictor de cuánta memoria usará un archivo. He visto archivos de menos de 5 MB que mastican más de 800 MB. cuando se cargan porque sus dimensiones son muy grandes. – Keith

4

Puede usar la clase MemoryFailPoint para verificar la disponibilidad de la memoria.

Mejor

+2

Por favor, todos lean cómo funciona esto, es por mucho la mejor manera de manejar grandes asignaciones de memoria de una manera "try/catch" – Spence

+0

Voy a ver esto. Un vistazo rápido me hace pensar que podría no ser lo que necesito ya que la documentación dice que necesitaría especificar "la cantidad de megabytes de memoria que se espera que la operación use". El problema es que no sé cuánta memoria va a llevar GDI +. para usar cuando carga la imagen usando System.Drawing.Image.FromStream. – Keith

1

ya he acordado con la respuesta @Vagaus, pero quería añadir que sólo se debe asignar el almacenamiento intermedio de una vez y tratar de volver a utilizarlo. Si está asignando y liberando constantemente un gran buffer, sin duda llegará a un problema OOM debido a la fragmentación en el montón.

+0

Hacemos uso de esta técnica cuando estamos descargando estos iamges. Sin embargo, estoy bastante seguro de que System.Drawing.Image.FromImage hace uso de eso s propio buffer interno que conduce a la fragmentación del montón de todos modos. – Keith

+0

¿Está llamando a TODOS los eliminadores en el material de GDI? Me he quemado antes, casi cada pequeña clase en las bibliotecas de GDI + requiere una llamada a deshacerse para liberar la memoria no administrada. ¿Quizás está perdiendo memoria debido a esto, causando el OOM? – Spence

+0

Estoy seguro de que estamos eliminando todos nuestros objetos correctamente. Tenemos usuarios que pueden pasar horas mirando imágenes de tamaño normal y la huella de memoria permanece constante. Solo existe la imagen ocasional con enormes dimensiones que engulle toda la memoria restante. – Keith

Cuestiones relacionadas