Forma correcta de eliminar Imagen / Mapa de bits y PictureBox

Estoy tratando de desarrollar una aplicación Windows Mobile 6 (en WF / C #). Solo hay un formulario y en el formulario solo hay un objeto PictureBox. En él dibujo todos los controles deseados o lo que quiera.

Hay dos cosas que estoy haciendo. Dibujar formas personalizadas y cargar mapas de bits desde archivos .png.

La siguiente línea bloquea el archivo al cargar (que es un escenario no deseado):

Bitmap bmp = new Bitmap("file.png"); 

Entonces estoy usando otra forma de cargar bitmap.

 public static Bitmap LoadBitmap(string path) { using (Bitmap original = new Bitmap(path)) { return new Bitmap(original); } } 

Supongo que esto es mucho más lento, pero no conozco una forma mejor de cargar una imagen, mientras que rápidamente se libera el locking de archivos.

Ahora, cuando dibujo una imagen, hay un método que uso:

 public void Draw() { Bitmap bmp = new Bitmap(240,320); Graphics g = Graphics.FromImage(bmp); // draw something with Graphics here. g.Clear(Color.Black); g.DrawImage(Images.CloseIcon, 16, 48); g.DrawImage(Images.RefreshIcon, 46, 48); g.FillRectangle(new SolidBrush(Color.Black), 0, 100, 240, 103); pictureBox.Image = bmp; } 

Sin embargo, esto parece ser algún tipo de pérdida de memoria. Y si sigo haciéndolo durante demasiado tiempo, la aplicación finalmente se bloquea.

Por lo tanto, tengo 3 preguntas:

1.) ¿Cuál es la mejor manera de cargar mapas de bits desde archivos sin bloquear el archivo?

2.) ¿Qué objetos deben eliminarse manualmente en la función Draw () (y en qué orden) para que no haya pérdida de memoria ni lanzamiento de ObjectDisposedException?

3.) Si pictureBox.Image se establece en bmp, como en la última línea del código, pictureBox.Image.Dispose () descartaría solo los recursos relacionados con el mantenimiento de pictureBox.Image o el bitmap subyacente establecido en él?

    1: No sé si funciona en WM pero prueba esto:

     FileStream bitmapFile = new FileStream("mybitmap.bmp", FileMode.Open, FileAccess.Read, FileShare.ReadWrite); Image loaded = new Bitmap(bitmapFile); 

    2: SolidBrush debe ser eliminado. Hay una regla general para disponer. -> “cada objeto, instanciado por usted, que implements dispose debe eliminarse manualmente, excepto cuando el objeto es un valor de retorno / ref / out”

    En este caso, es mejor usar una sentencia using

     using (new objecttodispose){ ..... } 

    La sentencia using asegurará la llamada de Dispose() en cualquier caso (excepción, por ejemplo).

    3: Dispose() liberará los recursos de bitmap.

    No creo que haya una fuga de memoria real. El problema es que no eliminas el viejo bitmap, depende del GC limpiarlo. Pero no hay una forma determinista de decir cuándo sucederá esto.

    Así que creo que si vas a recorrer muchas imágenes, verás que aumenta la memoria y en algún otro punto caerá o resistirá en una posición.

    No lo probé, pero tal vez esto ayude un poco a que sea más determinista:

     public void Draw() { Bitmap bmp = new Bitmap(240,320); using(var g = Graphics.FromImage(bmp)) using(var solidBrush = SolidBrush(Color.Black)) { // draw something with Graphics here. g.Clear(Color.Black); g.DrawImage(Images.CloseIcon, 16, 48); g.DrawImage(Images.RefreshIcon, 46, 48); g.FillRectangle(solidBrush, 0, 100, 240, 103); //Backup old image in pictureBox var oldImage = pictureBox.Image; pictureBox.Image = bmp; //Release resources from old image if(oldImage != null) ((IDisposable)oldImage).Dispose(); } } 

    Actualizar

    Y otra idea inspirada en jack30lena:

     public static Bitmap LoadBitmap(string path) { //Open file in read only mode using (FileStream stream = new FileStream(path, FileMode.Open, FileAccess.Read)) //Get a binary reader for the file stream using (BinaryReader reader = new BinaryReader(stream)) { //copy the content of the file into a memory stream var memoryStream = new MemoryStream(reader.ReadBytes((int)stream.Length)); //make a new Bitmap object the owner of the MemoryStream return new Bitmap(memoryStream); } } 

    La idea detrás de mi segundo ejemplo de código es deshacerse del identificador de archivo y copiar el contenido del archivo en la memoria. Después, el bitmap asumirá la propiedad del MemoryStream que se eliminará en mi primera muestra llamando a oldImage.Dispose() .

    Al utilizar este enfoque, nunca debería haber más de dos imágenes en la memoria, que llevarían solo a OutOfMemoryExceptions por imágenes realmente grandes o una pequeña cantidad de RAM.