2009-12-22 15 views
8

He algún código que hace algo como esto (bits irrelevantes snipped):.Net constructor de la clase Bitmap (int, int) y (int, int, PixelFormat) lanza ArgumentException en perfecto estado argumentos

void foo(Bitmap bmp1, Bitmap bmp2) 
{ 
    Bitmap bmp3; 
    if(something) 
     bmp3 = new Bitmap(bmp1.Width, bmp1.Height + bmp2.Height); 
    else 
     bmp3 = new Bitmap(bmp1.Width, 18000); 
    (more stuff here that runs fine) 
} 

anywho la mayor parte del tiempo esto funcionó bien. Primero. A medida que el proyecto continuó, comenzó a fallar en la nueva línea Bitmap. El error que da es: "ArgumentException no fue manejado. El parámetro no es válido". No se menciona con qué parámetro tiene un problema ni nada. Estoy perplejo. Esto es lo que sé con certeza:

  1. BMP1 y BMP-2 nunca han sido nula cuando se produce este error.
  2. La presencia de la declaración if tiene nunca marcó la diferencia; muere con la misma frecuencia sin.
  3. Ambos ejemplos del uso del constructor han arrojado este error.

Estoy tentado de decir que esto es un error de memoria, excepto que no menciona nada por el estilo. La primera docena de veces que sucedió esto, las alturas sumaron más de 18000 (de ahí el número mágico anterior). Pensando que era una especie de barrera blanda para nuestro sistema, limitamos las imágenes a esa altura, lo que hizo que las excepciones desaparecieran después de un tiempo.

Para algunos datos de ejemplo, la excepción que estoy viendo en este momento tiene bmp1.Width en 2550, en 6135 y bmp1.Height bmp2.Height en 6285.

Alguien tiene alguna idea?

Respuesta

19

GDI + no genera muy buenos mensajes de excepción. La excepción que tienes es escamosa, éste va a generar de forma fiable en mi máquina:

private void button1_Click(object sender, EventArgs e) { 
     var bmp = new Bitmap(20000, 20000); 
    } 

Lo que realmente está sucediendo es que este mapa de bits requiere demasiada memoria no administrado contigua para almacenar los bits de mapa de bits, más que está disponible en su proceso. En un sistema operativo de 32 bits, solo se puede esperar asignar un trozo de memoria alrededor de 550 megabytes. Eso va rápidamente cuesta abajo desde allí.

El problema es la fragmentación del espacio de direcciones, la memoria virtual de su programa almacena una combinación de código y datos en varias direcciones. El espacio de memoria total es de alrededor de 2 gigabytes, pero el agujero más grande es mucho más pequeño que eso. Solo puede consumir toda la memoria con muchas asignaciones pequeñas, las grandes fallan mucho más rápido.

En pocas palabras: está intentando decirte que el tamaño solicitado no puede ser compatible.

Un sistema operativo de 64 bits no tiene este problema. Asegúrese de aprovecharlo con Project> Properties> Build tab, Platform target = AnyCPU y Prefer 32-bit = sin marcar. Además, WPF confía en WIC, una biblioteca de creación de imágenes que es mucho más inteligente acerca de la asignación de almacenamientos intermedios para mapas de bits.

+0

Esto, junto con el enlace de Kyralessa, explicaba bastante el problema. Ahora solo tengo que arreglar la fuga de memoria. :(¡Gracias chicos! –

+1

En realidad, estoy teniendo este mismo problema depurando con VisualStudio en Widows7 64 bits. Por lo tanto, un sistema operativo de 64 bits no lo previene por completo. –

+1

Cambia la configuración de destino de la plataforma de tu proyecto EXE a AnyCPU para que realmente aproveches de un espacio de direcciones de 64 bits. –

0

¿Alguien tiene alguna idea?

Wrap la llamada que efectúa el lanzamiento ArgumentException con un try-catch(Exception ex) y paso en el bloque de excepción para ver la excepción prima. Es debería darle más detalles, como qué argumento es supuestamente inválido.

try 
{ 
    bmp3 = new Bitmap(bmp1.Width, bmp1.Height + bmp2.Height); 
} 
catch (Exception ex) 
{ 
    throw; // breakpoint here, examine "ex" 
} 
+0

Derecha. Debería haber mencionado que he intentado esto. Me da casi no más información. No hay excepción interna, el mensaje (en su totalidad) es "El parámetro no es válido.", La fuente está etiquetada como "System.Drawing", y el seguimiento de la pila tiene "en System.Drawing.Bitmap..ctor (Int32 width, Altura Int32, formato PixelFormat) "en el nivel superior. No estoy seguro de qué más podría obtener de la excepción. –

+0

Eso es interesante. Y por * interesante * quiero decir, "Que puedas llevar una vida interesante" -interesante. Dos de los constructores 'ArgumentException' aceptan una cadena parameterName, y es * interesante * que el constructor' Bitmap' no la usa cuando está claramente disponible. – JMD

+0

¿Alguna solución para este problema? – FabianoLothor