I have below method that is called. Within it I create a Bitmap local variable and then it is passed as an argument to an instance of a custom class. My doubt is: Do I have to dispose bitmap object?
public void AddSnapshot(int width, int height)
{
Bitmap bmp = null;
try
{
bmp = new Bitmap(width, height);
MyClass mc = new MyClass(bmp);
}
catch (Exception)
{
if (bmp != null) bmp.Dispose();
}
}
Reagrding to MSDN, not only in this case of an exception you should dispose it.
"Always call Dispose before you release your last reference to the
Image. Otherwise, the resources it is using will not be freed until
the garbage collector calls the Image object's Finalize method."
As you do via:
bitmap.Dispose();
Regarding to: https://learn.microsoft.com/de-de/dotnet/api/system.drawing.bitmap?view=netframework-4.7.2
Bitmap is derived from Image, and MSDN says you should call Dispose() on Images.
Related
I'm a newby in C#. I have to repeatedly refresh a GUI picture box in a worker thread. The image is acquired from a camera polling a driver with a GetImage method that retrives the image to be displayed. Even if I allocate the bitmap using directive "using" and explicitly call G.C, memory seems to be never deallocated.
The worker thread is something like this:
while (true)
{
// request image with IR signal values (array of UInt16)
image = axLVCam.GetImage(0);
lut = axLVCam.GetLUT(1);
DrawPicture(image, lut);
//GC.Collect();
}
While the DrawPicture method is something like
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());
}
}
Problems arises with the
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
In fact commenting that line of code, garbage collection works as it would.
Better, the problem seems to be with
System.Drawing.Image.FromHbitmap(bmp.GetHbitmap())
Any advice to solve this memory leak?
Thanks a lot!
Image implements IDisposable, so you should call Dispose on each Image instance that you create, when it is no longer needed. You could try to replace this line in your code:
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
With this:
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
This will dispose the previous image (if any) before the new one is assigned.
The thing is, you're making a GDI bitmap of bmp with GetHbitmap, which according to msdn:
You are responsible for calling the
GDI DeleteObject method to free the
memory used by the GDI bitmap object.
Then the FromHbitmap method makes a copy of the GDI bitmap; so you can release the incoming GDI bitmap using the GDI DeleteObject method immediately after creating the new Image.
So basically I would add:
[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);
I am unsure if you need the GDI bitmap to perform some kind of transformation. In case you don't you can just assign the bitmap to the Image property of your PictureBox, and ignore the former solution:
// 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;
There are several ways to release an image from pbox. I strongly recommend the way is that do not use pbox.Image = Image.FromFile.... If you do not use FileStream and you want to read it from file use BitMap class. Like this:
Bitmap bmp = new Bitmap(fileName);
pbox.Image = bmp; // notice that we used bitmap class to initialize pbox.
... and then you want to release the image file bmp.Dispose();
Now you can delete, move or whatever you want to the file.
In my WPF application images are taken with a camera use a view and then passed as bitmaps to another when it's closed via eventargs. However, when I then try to process the images I get the AccessViolationException. This does not occure when I process the images before they are passed or when I use images loaded from a file.
Getting the image from the camera (The PtCamera class is my wrapper for the Camera class from the API)
Bitmap GetRefImage(PtCamera cam)
{
Bitmap image = new Bitmap(2560, 1920, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
if (cam.IsConnected)
{
cam.FetchImage(out image);
}
else
{
ErrorOccurred?.Invoke(this, $"GetRefImage: {cam.Error}");
}
return image;
}
In this context I can access the bitmap and process it as I like.
After passing the bitmap when the view is closed:
void CloseZoomedView(bool isConf)
{
if (cam is object && cam.IsConnected)
cam.Close();
ZoomClosingArgs eArg = new ZoomClosingArgs()
{
IsConfirmed = isConf,
RefImage = refImage,
};
ClosingZoom?.Invoke(this, eArg);
}
The exception occurs directly when accessing the data in the other viewmodel:
void HandleZoomImageClosed(object sender, ZoomClosingArgs e)
{
if (e is object && e.IsConfirmed)
{
Color test = e.RefImage.GetPixel(0, 0);
//...
}
}
The bitmap is generated by accessing the memory of the camera via FetchImage()
public void FetchImage(out Bitmap image)
{
camera.Memory.GetActive(out int memID);
camera.Memory.ToBitmap(memID, out image);
}
If i replace the code in FetchImage() with just a new Bitmap from file
image = new Bitmap(#"d:\testimage.png")
It works without problems in any context.
The API documentation simply states the following:
Accessible
Camera.Memory.ToBitmap
Syntax
uEye.Memory.ToBitmap(int s32MemId, out System.Drawing.Bitmap bitmap)
Description
Returns a bitmap which contains the image. The method uses the already
allocated image memory and the image is displayed in the format you
specified when allocating the image memory.
Any hints are much appreciated.
I was closing my camera object too early. In CloseZoomedView() the cam.Close() method releases all the memory areas taken up by the camera. With passing a new Bitmap before closing it works like a charm.
void CloseZoomedView(bool isConf)
{
ZoomClosingArgs eArg = new ZoomClosingArgs()
{
IsConfirmed = isConf,
RefImage = new Bitmap(refImage),
};
if (cam is object && cam.IsConnected)
cam.Close();
ClosingZoom?.Invoke(this, eArg);
}
I have a Bitmap that I'm trying to save and I keep getting the "Object is currently in use elsewhere" error. Now I know GDI+ sucks with threading and that I'm supposed to use the lock{} statement but it's not working. My code is below, what am I doing incorrectly?
Bitmap bitmap = new Bitmap();
lock (bitmap)
{
bitmap.Save([filepath], ImageFormat.Png);
}
You should lock other dummy object:
var objectForLock = new object()
lock (objectForLock)
{
Bitmap bitmap = new Bitmap();
bitmap.Save([filepath], ImageFormat.Png);
}
Not sure if that's your problem, but that's the way lock works in .Net.
You should not lock on the object you are trying to lock. You should create a new reference and lock on that instead.
object bitmapLock = new object();
Bitmap bitmap = new Bitmap();
lock (bitmapLock)
{
bitmap.Save([filepath], ImageFormat.Png);
}
The bitmap might lock in different places that are beyond your control.
Read about the lock statement here.
Edit you might have to modify the bitmap on the thread that it was created.
http://msdn.microsoft.com/en-us/library/c5kehkcz(v=vs.80).aspx
You should lock synchronize before you initialize the Bitmap.
You need to have lock around all operations, not just Save. Locking for just save will not block other threads from manipulating the Bitmap.
Note that it is better to lock on separate object as everyone recommends.
// class member (or even static)
private object bitmapLock = new object();
// function 1
lock (bitmapLock)
{
bitmap.Save([filepath], ImageFormat.Png);
}
// function 2
lock (bitmapLock)
{
// Draw bitmap
}
I'm a newby in C#. I have to repeatedly refresh a GUI picture box in a worker thread. The image is acquired from a camera polling a driver with a GetImage method that retrives the image to be displayed. Even if I allocate the bitmap using directive "using" and explicitly call G.C, memory seems to be never deallocated.
The worker thread is something like this:
while (true)
{
// request image with IR signal values (array of UInt16)
image = axLVCam.GetImage(0);
lut = axLVCam.GetLUT(1);
DrawPicture(image, lut);
//GC.Collect();
}
While the DrawPicture method is something like
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());
}
}
Problems arises with the
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
In fact commenting that line of code, garbage collection works as it would.
Better, the problem seems to be with
System.Drawing.Image.FromHbitmap(bmp.GetHbitmap())
Any advice to solve this memory leak?
Thanks a lot!
Image implements IDisposable, so you should call Dispose on each Image instance that you create, when it is no longer needed. You could try to replace this line in your code:
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
With this:
if (pic.Image != null)
{
pic.Image.Dispose();
}
pic.Image = System.Drawing.Image.FromHbitmap(bmp.GetHbitmap());
This will dispose the previous image (if any) before the new one is assigned.
The thing is, you're making a GDI bitmap of bmp with GetHbitmap, which according to msdn:
You are responsible for calling the
GDI DeleteObject method to free the
memory used by the GDI bitmap object.
Then the FromHbitmap method makes a copy of the GDI bitmap; so you can release the incoming GDI bitmap using the GDI DeleteObject method immediately after creating the new Image.
So basically I would add:
[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);
I am unsure if you need the GDI bitmap to perform some kind of transformation. In case you don't you can just assign the bitmap to the Image property of your PictureBox, and ignore the former solution:
// 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;
There are several ways to release an image from pbox. I strongly recommend the way is that do not use pbox.Image = Image.FromFile.... If you do not use FileStream and you want to read it from file use BitMap class. Like this:
Bitmap bmp = new Bitmap(fileName);
pbox.Image = bmp; // notice that we used bitmap class to initialize pbox.
... and then you want to release the image file bmp.Dispose();
Now you can delete, move or whatever you want to the file.
I have a windows form where I set the BackgroundImage property to a custom bitmap image.
private Image MakeCustomBackground()
{
Bitmap result = new Bitmap(100, 100);
using(Graphics canvas = Graphics.FromImage(result))
{
// draw the custom image
}
return result;
}
private void UpdateFromBackground()
{
this.BackgroundImage = MakeCustomBackground();
}
My question is, Image is disposable and I am creating it, does that mean that I must dispose of it? Or when I pass the image to the form, via BackgroundImage, does it take ownership and dispose of it when it no longer needs it?
Assuming that UpdateFromBackground() is called more than once, you probably should Dispose the old Image when (before) setting a new one. If you don't then the GC will do it eventually but that is less efficient. The Form will only Dispose the last BgImage you assigned.
private void UpdateFromBackground()
{
if (this.BackgroundImage != null)
{
this.BackgroundImage.Dispose();
}
this.BackgroundImage = MakeCustomBackground();
}