C# Usercontrol's memory leak - c#

I have some heavy memory leak in my application.
This is the form that loads a lot of stuff in memory, it is a form with 3 FlowLayoutPanel. Every panel has a lot of a UserControl I've created, they're just a picturebox with a label. Let's call the form ColorViewer:
Whenever I open this form it takes close to 300-400 MB of memory and it doesn't seems to release it.
This a graph of the memory usage:
As you can the first time I open ColorViewer it loads everything in memory (close to 400mb) and then it never dispose. After that, every time I open ColorViewer it is disposed correctly.
This is the code I use to load my form, I guess the memory leak is in the loading of the img. As of right now I use the default Dispose():
//Loading of one of the three panel in the form,called 3 time when the form is opened:
colorsViewerPanel.AddColorRange(colours.ConvertAll(x => new ColorBox(x.path_img, x.id,true)));
//Function that loads my UserControl into the panel
public void AddColorRange(List<ColorBox> cBoxList)
{
flowLayoutPanel1.SuspendLayout();
foreach (var cBox in cBoxList)
flowLayoutPanel1.Controls.Add(cBox);
flowLayoutPanel1.ResumeLayout();
}
//This is the ColorBox usercontrol's class
public string pathImg{ get; set; }
public int id{ get; set; }
public bool selected{ get; set; }
//This is the constructor for the UserControl
public ColorBox(string pathImage,int idImage,bool sel = true)
{
InitializeComponent();
pathImg = pathImage;
id = idImage;
selected = sel;
//Load img
if (File.Exists(pathImg))
{
Image img;
using (var bmpTemp = new Bitmap(pathImg))
{
img = new Bitmap(pathImg);
}
panelColor.BackgroundImage = img;
panelColor.BackgroundImageLayout = ImageLayout.Stretch;
labelColor.Text = id;
}
}
Is this normal ?

I think you are not disposing anything useful here:
Image img;
using (var bmpTemp = new Bitmap(pathImg))
{
img = new Bitmap(pathImg);
}
you are just creating an instance (bmpTemp) of the Bitmap class (that is later going to be disposed because of the using statement) and then assigning a new istance of the same class to another variable (img, the one you are effectively using). Anyway, even if you correct this, it will not work for your purposes, because there's no meaning in disposing the Image you are actually showing in a PictureBox (and this will also lead to an exception later on).
As you can read here, it is necessary to call Dispose on an Image object to effectively get rid of its presence in memory, keeping in mind that Bitmap is a wrapper around an unmanaged GDI+ bitmap (and probably requires special needs to get disposed even when wrapped):
Image.Dispose()
That said, given the code you provided and to cut the problem at the root, I guess I would probably implement the IDisposable interface on the ColorBox control to make sure the Dispose method of the Image instance is always called when the control is disposed:
Implement IDisposable correctly
In your specific case, I would consider the Image/Bitmap object as a fully unmanaged object and I would free it in the "free native resources if there are any" section of the Dispose method so that, if someone is using your control without disposing it, the call to the finalizer is going to happen anyway if the object is eligible for finalization. Something like this:
// The bulk of the clean-up code is implemented in Dispose(bool)
protected virtual void Dispose(bool disposing)
{
if (isDisposed) return;
if (disposing)
{
// free managed resources
managedResource.Dispose();
}
// free native resources if there are any.
if (!(img is null))
{
// Our Image.
img.Dispose();
}
isDisposed = true;
}

Related

AForge, memory stacking up

Im trying to grab a frame with C# and AForge libraries:
...
using AForge.Video
using AForge.Video.DirectShow
namespace Example
{
class Program
{
private static Bitmap mySnap = null;
static void Main(string[] args)
{
snapByte();
}
private static void snapByte()
{
int Counter = 0;
FilterInfoCollection videoDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
VideoCaptureDevice videoSource = new VideoCaptureDevice(videoDevices[0].MonikerString);
videoSource.NewFrame += new NewFrameEventHandler(videoNewFrame);
videoSource.Start();
do
{
Thread.Sleep(500);
Counter++;
}
while (mySnap == null && Counter < 4);
if (videoSource.IsRunning)
{
videoSource.SignalToStop();
videoSource.WaitForStop();
videoSource = null;
}
MemoryStream myStream = new MemoryStream();
mySnap.Save(myStream, ImageFormat.Png);
byte[] snapByteLength = MyStream.ToArray();
int snapLength = snapByteLength.Length;
Console.WriteLine(snapLength);
Console.ReadLine();
myStream.Dispose();
mySnap = null;
snapByte();
}
}
private static void videoNewFrame(object sender, NewFrameEventArgs eventArgs)
{
mySnap = (Bitmap)eventArgs.Frame.Clone();
}
}
}
this is the exact code im using, i just changed the image byte processing to display the byte length to simplify things..
the problem im having is that the memory will keep staking up anywhere between 1-2 mb each time a snapshot is taken..
i am disposing of all my bitmaps except for the mySnap that im returning to null.. i cant dispose of mySnap because its used again, and i have to declare it global because i use this in snapByte() and newVideoFrame()
but since im reusing mySnap i dont see why would it be stacking up.. it should be overwriting everytime..
i have seen other answers but all have to do with a picturebox, and the answer is to clear the picturebox before loading a new image..
i believe im doing the equivalent here by calling mySnap=null again..
but memory still stacking up...
Thank You..
You are creating an infinite recursion by your unconditional call to snapByte() at the end of the snapByte() method. This creates a loop that will eventually crash once your stack runs out of space; every time your method calls itself, you are setting up a new stack frame that will never be cleared because the method never returns. This may take a while to manifest because of the Thread.Sleep() call that will keep your recursive calls throttled.
Also, any reference that was not nulled before you recursively call snapByte() will be held indefinitely in memory, since those references are alive in a scope that will never exit (because of the infinite recursion) and will never be reclaimed by the GC.
This is the case for your videoDevices collection but more importantly for the snapByteLength array instance, that is holding a copy of the bitmap you just captured. I bet this is the primary cause for your memory leak
Avoiding recursion and converting it to a simple loop should fix your issues.

ArgumentException on Image.Dispose()

I am making an album application with windows forms and I have a problem that I can't solve. First of all I have a form where I create a TableLayoutPanel. After that I create a method where I generate the same amount of picture boxes as the amount of the images in the directory which I have opened. The problem occurs when I am trying to dispose the image which I load in the picturebox because I need to free its memory. Here is the code of the method:
public void createPictureBoxes()
{
Image loadedImage;
int imageCounter = 0;
for (int i = 0; i < rowCounter; i++)
for(int p = 0; p < imagesTable.ColumnCount; p++)
{
PictureBox pb = new PictureBox();
pb.SizeMode = PictureBoxSizeMode.Zoom;
pb.Width = imagesTable.GetColumnWidths()[p];
pb.Height = imagesTable.GetRowHeights()[i];
pb.Click += new EventHandler(enlargeThumbnail);
try
{
loadedImage = Image.FromFile(images[imageCounter++]);
pb.Image = loadedImage;
loadedImage.Dispose();
imagesTable.Controls.Add(pb);
loadedImage.Dispose();
}
catch (IndexOutOfRangeException)
{
break;
}
}
}
The program throws an ArgumentException on method Show() of the form telling me that the argument is not valid. Without the dispose method all works fine but if i try to load a large amount of images the program uses gigabytes of memory. I suppose that it is not right to dispose the image memory that way, but I can't come out with another idea. If someone could help I would be very grateful
Two problems: you're disposing twice, and further you won't be able to dispose of an image control so long as a parent control container is expected to use it. When the form is disposed then it will cause all controls to be disposed that are part of its container.
So, much less than trying to dispose twice, don't dispose at all (here, that is)!
You can't dispose the image while you are displaying it. If you do, the form can't display it.
The PictureBox doesn't make a copy of the Image instance when you assign it to the Image property. It keeps the instance, so you can't dispose it until you have removed the image from the picture box.

.NET PictureBox - how to be sure that the resource is released

I have an OpenFileDialog and PictureBox in user control. To understand the problem better I'll explain in few words how this user control works. The user can select an image to be opened for the form. The name of this image is saved in a DataBase and the file for the image is copied in a default location. When there is some image saved in the database it is load in the picturebox when the form with the picturebox control is loaded. If the user select another image and want to save the form with the new image I have a method that takes care to delete the old image file from my default location and that is where the problem occurs.
When I have loaded image and try to save new one, sometimes (very rare in fact) I get an error that The resource is being used by another process.. I can paste the exact error if needed. I think that the problem is caused from the picturebox and the way it deals with images.
Here is my code:
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
try
{
if (MyImage != null)
{
MyImage.Dispose();
}
selectedFile = openFileDialog1.FileName;
selectedFileName = openFileDialog1.SafeFileName;
MyImage = new Bitmap(openFileDialog1.FileName);
pictureBox1.Image = (Image)MyImage;
int imageWidth = pictureBox1.Image.Width;
int picBoxWidth = pictureBox1.Width;
if (imageWidth != 0 && picBoxWidth > imageWidth)
{
pictureBox1.Width = imageWidth;
}
else
{
pictureBox1.Width = defaultPicBoxWidth;
}
}
catch (Exception ex)
{
logger.Error(ex.ToString());
MessageBox.Show("Error loading image!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
and my delete method:
public void DeleteImage(AppConfig imageInfo, string imageName)
{
string imgPath = imageInfo.ConfigValue.ToString();
try
{
File.Delete(imgPath + "\\" + imageName);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
I thought that :
if (MyImage != null)
{
MyImage.Dispose();
}
will deal with this problem but still sometimes it occurs. And because it's not everytime it's even more critical to deal with it because at some point I may decide that I have solved it but in fact to be just lucky for some time.
MyImage = new Bitmap(openFileDialog1.FileName);
pictureBox1.Image = (Image)MyImage;
Yes, that code puts a lock on the file. The lock is produced by a memory mapped file object that GDI+ creates to efficiently map the pixel data of the file into memory without having to allocate space in the paging file. You will not be able to delete the file as long as the image is displayed in the picture box and not disposed, the lock prevents that. You will have to dispose the image and set the Image property back to null before you can delete the file.
You can prevent the file from getting locked by making an in-memory copy of the image:
using (var temp = new Bitmap(openFileDialog1.FileName)) {
pictureBox1.Image = new Bitmap(temp);
}
It is not as efficient of course, to be avoided if the image is large. And do beware that another process may in fact have a similar lock on the file. Nothing you can do about that.
A major difficulty with things like PictureBox is that because a PictureBox has no way of knowing whether it is the only user of an image, it consequently has no way of knowing whether it should dispose of that image when it no longer needs it.
Consequently, whatever code owns a picture box must also take ownership of the image associated therewith. There are three approaches I could suggest for doing so:
Create a control derived from PictureBox which documents itself as assuming ownership of any image given to it. Such a control should probably replace the image property with a SetImageWithOwnership method (with the semantics that once an image is passed to the PictureOwningBox, the box will be expected to "own" it, and will dispose it either when the box is Disposed or when a different image is given to the box).
Attach event handlers to a PictureBox to handle the scenarios where either the box is destroyed or a different image is assigned to it.
Have any code which would cause the PictureBox to be disposed or have a different image loaded, also dispose the Image that had been assigned to it.
While there may be cases where it would be appropriate to call GC.Collect and let the garbage-collector take care of things, such an approach is generally unsound.
try that:
using(Bitmap MyImage = new Bitmap(openFileDialog1.FileName))
{
pictureBox1.Image = (Image)MyImage;
int imageWidth = pictureBox1.Image.Width;
int picBoxWidth = pictureBox1.Width;
if (imageWidth != 0 && picBoxWidth > imageWidth)
{
pictureBox1.Width = imageWidth;
}
else
{
pictureBox1.Width = defaultPicBoxWidth;
}
}
I've had problems like this before, and one way that I've found to make sure that the resource is released, even after Dispose(), which really only marks the object for removal by the garbage collector, is by using GC.Collect(). I'm sure that there is a cleaner way to handle the resource disposal, but the time that it takes the GC.Collect() to run shouldn't hinder your program.

What is the correct pattern to use when multiple events can cause a calculation?

I've been having a lot of annoying problems with accessing bitmaps lately and I'm starting to think I need to re-evaluate the design of my application.
At present, I have one object that creates two others. One of these others provides a series of bitmaps (e.g. from a webcam) and the other provides a series of coordinate pairs (e.g. from a mouse or touchpad). The parent object has listeners for the events that the children objects generate. The events are have custom arguments which carry the new information (bitmap or coordinates) as a payload. For instance:
public class NewImageEventArgs : EventArgs
{
public NewImageEventArgs(Bitmap image)
{
Image = image;
}
public Bitmap Image { get; private set; }
}
The listener methods in the parent object copy the payload to the object-level representation. When either listener (bitmap or coordinates) is triggered, they subsequently call a shared method, which uses both the bitmap and the coordinates to do some calculation.
private void PointerModule_NewPosition(object sender, NewPositionEventArgs e)
{
this.p = e.Position;
this.Invalidated();
}
It seems to me that my recurring problems with OutOfMemory and InvalidOperation ("Object is currently in use elsewhere") exceptions stem from the fact that each new event may be on a different thread. When a bitmap is being used on one thread, exceptions are raised when another thread tries to simultaneously access it.
Do I need to fundamentally change the shape of my program? Are there any precautions I can take to eliminate this type of problem?
EDIT:
I reread your question and I might have responded to a slightly different question than you've asked. However I fought the same problems with "Object is used elsewhere" exceptions and the lesson I learned is summarized in the link in the bottom. Neither bitmap.Clone() nor new Bitmap(source) creates deep image copy. This is causing the exceptions.
In my application I use pattern :
public class ImageProvider()
{
public event EventHandler LiveImageUpdated;
private object _currentImageLock = new object();
private Bitmap _currentImage;
public Bitmap CurrentImage
{
get
{
lock (_currentImageLock)
{
return DeepImageCopy(_currentImage)
}
}
private set
{
lock(_currentImageLock)
{
_currentImage = value
}
if (LiveImageUpdated != null)
{
foreach (Delegate del in LiveImageUpdated.GetInvocationList())
{
EventHandler handler = (EventHandler)del;
handler.BeginInvoke(this, EventArgs.Empty, null, null);
}
}
}
}
}
And I asked this question :
How to create a Bitmap deep copy
Application works without a problem. So basically I skipped the part with pushing new image as an argument and listeners are asking for deep copy of the image and they are not sharing images. Performancewise it works without a problem.

GC contains lots of pinned objects after a while

I have a strange phenomenon while continuously instantiating a com-wrapper and then letting the GC collect it (not forced).
I'm testing this on .net cf on WinCE x86. Monitoring the performance with .net Compact framework remote monitor. Native memory is tracked with Windows CE Remote performance monitor from the platform builder toolkit.
During the first 1000 created instances every counter in perfmon seems ok:
GC heap goes up and down but the average remains the same
Pinned objects is 0
native memory keeps the same average
...
However, after those 1000 (approximately) the Pinned object counter goes up and never goes down in count ever again. The memory usage stays the same however.
I don't know what conclusion to pull from this information... Is this a bug in the counters, is this a bug in my software?
[EDIT]
I do notice that the Pinned objects counter starts to go up as soon the total bytes in use after GC stabilises as does the Objects not moved by compactor counter.
The graphic of the counters http://files.stormenet.be/gc_pinnedobj.jpg
[/EDIT]
Here's the involved code:
private void pButton6_Click(object sender, EventArgs e) {
if (_running) {
_running = false;
return;
}
_loopcount = 0;
_running = true;
Thread d = new Thread(new ThreadStart(LoopRun));
d.Start();
}
private void LoopRun() {
while (_running) {
CreateInstances();
_loopcount++;
RefreshLabel();
}
}
void CreateInstances() {
List<Ppb.Drawing.Image> list = new List<Ppb.Drawing.Image>();
for (int i = 0; i < 10; i++) {
Ppb.Drawing.Image g = resourcesObj.someBitmap;
list.Add(g);
}
}
The Image object contains an AlphaImage:
public sealed class AlphaImage : IDisposable {
IImage _image;
Size _size;
IntPtr _bufferPtr;
public static AlphaImage CreateFromBuffer(byte[] buffer, long size) {
AlphaImage instance = new AlphaImage();
IImage img;
instance._bufferPtr = Marshal.AllocHGlobal((int)size);
Marshal.Copy(buffer, 0, instance._bufferPtr, (int)size);
GetIImagingFactory().CreateImageFromBuffer(instance._bufferPtr, (uint)size, BufferDisposalFlag.BufferDisposalFlagGlobalFree, out img);
instance.SetImage(img);
return instance;
}
void SetImage(IImage image) {
_image = image;
ImageInfo imgInfo;
_image.GetImageInfo(out imgInfo);
_size = new Size((int)imgInfo.Width, (int)imgInfo.Height);
}
~AlphaImage() {
Dispose();
}
#region IDisposable Members
public void Dispose() {
Marshal.FinalReleaseComObject(_image);
}
}
Well, there's a bug in your code in that you're creating a lot of IDisposable instances and never calling Dispose on them. I'd hope that the finalizers would eventually kick in, but they shouldn't really be necessary. In your production code, do you dispose of everything appropriately - and if not, is there some reason why you can't?
If you put some logging in the AlphaImage finalizer (detecting AppDomain unloading and application shutdown and not logging in those cases!) does it show the finalizer being called?
EDIT: One potential problem which probably isn't biting you, but may be worth fixing anyway - if the call to CreateImageFromBuffer fails for whatever reason, you still own the memory created by AllocHGlobal, and that will currently be leaked. I suspect that's not the problem or it would be blowing up more spectacularly, but it's worth thinking about.
I doubt it's a bug in RPM. What we don't have here is any insight into the Ppb.Drawing stuff. The place I see for a potential problem is the GetIImagingFactory call. What does it do? It's probably just a singleton getter, but it's something I'd chase.
I also see an AllochHGlobal, but nowhere do I see that allocation getting freed. For now that's where I'd focus.

Categories

Resources