Nyxojaele

It appears that I have some kind of memory leak in my code (to a degree).

I have an object that maintains unmanaged resources, this object has an init() and deinit() member function for allocating and deallocating those unmanaged resources. These resources are used to create a managed Bitmap. When allocated, the object takes about 8mb of RAM, so it's pretty obvious if it doesn't deallocate at some point.

Anyways, I've thrown together a couple lines of code to test and make sure all is going well, and this is my results:

Code Block

GC::Collect(); //Clearing memory before everything (~31mb used)
myObject->init(); //Uses ~8mb
//myPicturebox->Image = myObject->bmp; //Commented out for this example

//myPicturebox->Image = nullptr; //Commented out for this example

myObject->deinit(); //Clears ~8mb

GC::Collect(); //Clearing memory after everything (~31mb used)


This works fine- as you can see from my comments, the object init/deinits fine. The problem is if I uncomment those 2 lines of code, all they do is assign my created Bitmap to a picturebox, then unassign it again. But after Garbage Collecting when I've done that, my 8mb in my object isn't cleanup up anymore! (Which leads me to believe that somewhere in assigning my Bitmap to the picturebox, .NET keeps another reference to it somewhere, so it won't be GC'd...

Code Block

GC::Collect(); //Clearing memory before everything (~31mb used)
myObject->init(); //Uses ~8mb
myPicturebox->Image = myObject->bmp; //Assign to picturebox

myPicturebox->Image = nullptr; //Remove from picturebox

myObject->deinit(); //Doesn't clear ~8mb anymore!

GC::Collect(); //Clearing memory after everything (~39mb used)


My original test code had GC::Collect() calls between every line, so I could monitor exactly where RAM is allocated/freed, but I left them out for simplicity's sake in my examples.

Any thoughts


Re: Windows Forms General Object not being Garbage Collected, why?

Centuri0n

You need to remove link to image from myPicturebox too. If your picturebox is smaller than picture you better create new bitmap with size of picturebox and draw scaled image to it, and release original image after.

P.S. missed you acually did it. Try load and release 100 copies of image and see will memory takes in task manager will go up to 800mb or no, probably this picture is just cached for reason you load it again later in code somewhere





Re: Windows Forms General Object not being Garbage Collected, why?

Nyxojaele

Shouldn't simply setting PictureBox::Image to nullptr be enough to disconnect it from the Bitmap

The code samples I posted above were in the exact same spot in my code. All I did was uncomment those 2 lines. So if the image is cached cause it's being used later, it should be cached whether those lines are uncommented or not, no

Like I said, I can init() and deinit() (without assigning the Bitmap to a picturebox) the image until the cows come home, and it won't take up more memory, because it's correctly releasing the memory, it's just when I assign/unassign the image from a picturebox that I have this issue. And this memory NEVER seems to get released!

<EDIT>Okay, so I found a way to make it work, but I don't understand WHY it works this way- maybe somebody can help me here...

The actual situation around the code is this:
I have a tableLayoutPanel in which I dynamically create a picturebox- in this particular situation, the ONLY control in this tableLayoutPanel is this single picturebox. So my original code was this:

Code Block

//Create a picturebox

PictureBox ^thePicBox = gcnew PictureBox;

//Configure the picturebox

...

//Add the picturebox to the tableLayoutPanel

this->tableLayoutPanel1->Controls->Add(thePicBox);



//Image setup

Bitmap ^preview = theItem->init();
dynamic_cast<PictureBox ^>(this->tableLayoutPanel1->Controls[0])->Image = preview;

//Image cleanup

dynamic_cast<PictureBox ^>(this->tableLayoutPanel1->Controls[0])->Image = nullptr;
preview = nullptr;

theItem->deinit();

GC::Collect();



That code gives me the "memory leak". BUT, if I change the last few lines of code to this instead:

Code Block

//Image setup
Bitmap ^preview = theItem->init();
thePicBox->Image = preview;
//Image cleanup
thePicBox->Image = nullptr;
preview = nullptr;
theItem->deinit();
GC::Collect();

It all works well. I don't see why there should be a difference between accessing the PictureBox via the tableLayoutPanel, or directly...

Any thoughts

</EDIT>


<EDIT2>
On closer inspection, the only line that makes a difference is the one where I set the picturebox's image to nullptr

This is the weirdest thing ever. This is my original line- it doesn't work ("memory leak"):
Code Block

dynamic_cast<PictureBox ^>(this->tableLayoutPanel1->Controls[0])->Image = nullptr;


But these lines work perfectly fine! (*confused beyond belief!*)
Code Block

PictureBox ^thePB = dynamic_cast<PictureBox ^>(this->tableLayoutPanel1->Controls[0]);
thePB->Image = nullptr;


What's going on
</EDIT2>




Re: Windows Forms General Object not being Garbage Collected, why?

Centuri0n

There is a mark in msdn documentation about PictureBox.Image - that you need to keep stream of picture opened all the time while it's used in picturebox. No one could answer why.. And i guess you close stream, so it's worth a try to keep stream opened, and if you need lot of copies of same picture load them into MemoryStream and create Bitmap from it, instead of FileStrea