Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Right way to dispose Image/Bitmap and PictureBox

Tags:

I am trying to develop a Windows Mobile 6 (in WF/C#) application. There is only one form and on the form there is only a PictureBox object. On it I draw all desired controls or whatever I want.

There are two things I am doing. Drawing custom shapes and loading bitmaps from .png files.

The next line locks the file when loading (which is an undesired scenario):

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

So I am using another way to load bitmap.

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

This is I guess much slower, but I don't know any better way to load an image, while quickly releasing the file lock.

Now, when drawing an image there is method that I use:

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;  } 

This however seems to be some kind of a memory leak. And if I keep doing it for too long, the application eventually crashes.

Therefore, I have 3 questions:

1.) What is the better way for loading bitmaps from files without locking the file?

2.) What objects needs to be manually disposed in the Draw() function (and in which order) so there's no memory leak and no ObjectDisposedException throwing?

3.) If pictureBox.Image is set to bmp, like in the last line of the code, would pictureBox.Image.Dispose() dispose only resources related to maintaining the pictureBox.Image or the underlying Bitmap set to it?

like image 625
Kornelije Petak Avatar asked May 11 '10 07:05

Kornelije Petak


People also ask

Do I need to dispose bitmap?

You should dispose it after you have finished with it in the code where this method is called and ignore the warning. Actually, further investigation has revealed that warning to be not as ridiculous as it sounds. It's telling you that bitmap won't be disposed if there is an exception before the method returns.

What is image dispose?

The Dispose method leaves the Image in an unusable state. After calling Dispose, you must release all references to the Image so the garbage collector can reclaim the memory that the Image was occupying.


2 Answers

I don't think there is a real memory leak. The problem is that you don't dispose the old bitmap, it is up to the GC to clean the stuff. But there is no deterministic way to say when this will happen.

So i think if you're going to loop through a lot of pictures, you'll see some memory increase and at some other point it will fall down or resist at one position.

I didn't test it, but maybe this will help a little to make it more deterministic:

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();                 } } 

Update

And another idea inspired by 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);     } } 

The idea behind my second code sample is to get rid of the file handle and copy the file content into memory. Afterwards the Bitmap will taken ownership of the MemoryStream which will be disposed within my first sample by calling the oldImage.Dispose().

By using this approach there should never be more then two images in memory, thous leading only to OutOfMemoryExceptions by really big pictures or small amount of RAM.

like image 150
Oliver Avatar answered Sep 18 '22 23:09

Oliver


1: I dont know if it works in Windows Mobile but try this:

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

2: The SolidBrush must be disposed. There is a general rule for dispose. --> "every object, instanciated by you, that implements dispose must be disposed manually, exept when the object is a return/ref/out value"

In this case it is better to use a using statement

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

The using statement will ensure the call of Dispose() in any case (exception for example).

3: Dispose() will free the bitmap ressources.

like image 37
Jack Avatar answered Sep 16 '22 23:09

Jack