Pregunta

Soy un Newby en C #. Tengo que refrescar repetidamente un cuadro de imagen GUI en un subproceso de trabajo. La imagen se adquiere de una cámara de votación a un conductor con un método que GetImage retrives la imagen que se mostrará. Incluso si asigno el mapa de bits utilizando la directiva "por medio de" y llamar explícitamente G.C, la memoria parece ser que nunca desasignado.

El subproceso de trabajo es algo como esto:

   while (true)
    {
        // request image with IR signal values (array of UInt16)
        image = axLVCam.GetImage(0);
        lut = axLVCam.GetLUT(1);
        DrawPicture(image, lut);
        //GC.Collect();

    }

Mientras que el método DrawPicture es algo así como

   public void DrawPicture(object image, object lut)
{

  [...]

    // We have an image - cast it to proper type
    System.UInt16[,] im = image as System.UInt16[,];
    float[] lutTempConversion = lut as float[];

    int lngWidthIrImage = im.GetLength(0);
    int lngHeightIrImage = im.GetLength(1);

    using (Bitmap bmp = new Bitmap(lngWidthIrImage, lngHeightIrImage)) {

      [...many operation on bitmap pixel...]

        // Bitmap is ready - update image control

        //SetControlPropertyThreadSafe(tempTxtBox, "Text", string.Format("{0:0.#}", lutTempConversion[im[160, 100]]));

        //tempTxtBox.Text = string.Format("{0:00000}", im[160, 100]);
        //System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
        pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
    }
}

Los problemas surge con el

  

pic.Image = System.Drawing.Image.FromHbitmap (bmp.GetHbitmap ());

De hecho comentando esa línea de código, la recolección de basura funciona como lo haría. Mejor, el problema parece ser con

  

System.Drawing.Image.FromHbitmap (bmp.GetHbitmap ())

Cualquier consejo para resolver esta pérdida de memoria?

Muchas gracias!

¿Fue útil?

Solución

Image implementa IDisposable, por lo que debe llamar Dispose en cada instancia Image que se crea, cuando ya no se necesita. Se podría tratar de sustituir esta línea en su código:

pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());

Con esta:

if (pic.Image != null)
{
    pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());

Esto disponer la imagen anterior (si lo hay) antes de asignar el nuevo.

Otros consejos

Lo que pasa es que está haciendo un mapa de bits de GDI bmp con GetHbitmap, que de acuerdo con MSDN:

  

Usted es responsable de llamar al   GDI método para liberar el DeleteObject   memoria utilizada por el objeto de mapa de bits GDI.

A continuación, el método FromHbitmap hace una copia del mapa de bits GDI; por lo que puede liberar el mapa de bits GDI recibidas utilizando el método de GDI DeleteObject inmediatamente después de crear la nueva imagen.

Así que básicamente me gustaría añadir:

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

...

IntPtr gdiBitmap = bmp.GetHbitmap();

// Release the copied GDI bitmap
if (pic.Image != null)
{
    pic.Image.Dispose();
}

pic.Image = System.Drawing.Image.FromHbitmap(gdiBitmap);

// Release the current GDI bitmap
DeleteObject(gdiBitmap);

No estoy seguro de si necesita el mapa de bits GDI para llevar a cabo algún tipo de transformación. En caso de que no se puede simplemente asignar el mapa de bits a la propiedad de imagen del cuadro de imagen, e ignorar la primera solución:

// Since we're not using unmanaged resources anymore, explicitly disposing 
// the Image only results in more immediate garbage collection, there wouldn't 
// actually be a memory leak if you forget to dispose.
if (pic.Image != null)
{
    pic.Image.Dispose();
}

pic.Image = bmp;

Hay varias maneras de liberar una imagen de pbox. Recomiendo el camino es que no utilizan pbox.Image = Image.FromFile.... Si no se utiliza FileStream y quiere leerlo de utilización archivo de clase mapa de bits. De esta manera:

Bitmap bmp = new Bitmap(fileName);
pbox.Image = bmp; // notice that we used bitmap class to initialize pbox.

... y luego desea liberar el archivo de imagen bmp.Dispose();
Ahora se puede borrar, mover o como se quiera en el fichero.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top