.NET Form close/dispose does not deallocate global objects - c#

Edit: Please just take into consideration the sample I provided. There are no events being called. The code I provided is all that there is. I just want to know of global objects in a form must be manually de-allocated. It would be nice to also know why a form going out of scope doesn't get cleaned up, but that is secondary.
Closing or calling dispose on a Form does not seem to deallocate that form's global objects. I have a form that will be instantiated multiple times and after opening a number of times I am getting an OutOfMemory exception, even if all the previous forms were closed. I can get memory to free by making every object I am using disposable, but I thought in general the garbage collection took care of cleaning up objects out of scope.
Here is a simple example of a form with just a multidimensional double array:
using System;
using System.Windows.Forms;
namespace surGroupTool
{
public partial class TestForm : Form
{
double[,] testArray;
public TestForm()
{
InitializeComponent();
testArray = new double[5000, 5000];
}
}
}
When I create the form in an infinite loop it quickly runs out of memory, even if I dispose and set it to null.
while (true)
{
TestForm testForm = new TestForm();
testForm.Dispose();
testForm = null;
}
Must every object be manually disposed for a closed/disposed form?

I was unable to reproduce the issue with the given source code. This screenshot is from about 20 seconds. But I left it running while getting coffee and it was still fine. It was looping the memory pattern as shown above.
One thing I noticed is that it takes some time before the GC frees up memory. The GC only runs when your starting to get low on memory or when manually calling it with GC.Collect();. At that point a background process will start that does the actual cleaning. This garbage collection thread does not fully interrupt your programs main thread (according to the Microsoft documentation > background workstation garbage collection). So this means that it is possible to keep allocating memory even when the GC is running. At that point it is a race who's first. You in allocating enough memory to get out of bounds. or your GC with its cleanup.
Must every object be manually disposed for a closed/disposed form?
No, generally global resources do not have to be disposed. The GC will clean them up if nothing is referencing them. However if a global resources is an unmanaged resources (like a stream or a bitmap) you need to dispose it before it can be cleaned, this is the same for local unmanaged resource.
from the comments:
This happens even if each form is created by a user clicking a button...with minutes between forms being created.
I'm going to assume that this is in your real application and not with the form provided as a test sample. You are most likely leaving a reference to that form (for example via a dialog result, or open undamaged resource). If it is with the given form I cannot explain it and you might need to check if you haven't overwritten the GC settings to something very exotic, or disabled it all together.

Related

Is memory released on Form.close()?

I am working on feedback application which have lots of form open and close operation. I noticed few changes in memory changes in my application when i start my application it takes 25 MB. With each feedback user give it increases 3 MB in memory usage. On every form i had used this.close() when it jumps from one to other or there is any close operation. What can be the possible reason of memory increases.
Do i need to call garbage collector manually, as everyone says its not good practice.
In this i am using dual monitor scenario in which application take snapshot of secondary screen after each 500 ms and shows it on primary screen. For this I am using the code shown below:
public EntryForm()
{
sc = Screen.AllScreens;
dbDms = new HondaDb(UtilityFunctions.getServerConnection());
db = new HondaDb(UtilityFunctions.getClientConnection());
bmpScreenshot = new Bitmap(sc[1].Bounds.Width,
sc[1].Bounds.Height,
PixelFormat.Format32bppArgb);
Create a graphics object from the bitmap.
gfxScreenshot = Graphics.FromImage(bmpScreenshot);
Timer timerClientScreen = new Timer();
timerClientScreen.Interval = 500;
timerClientScreen.Enabled = false;
timerClientScreen.Start();
timerClientScreen.Tick += new EventHandler(timer_TickClient);
}
void timer_TickClient(object sender, EventArgs e)
{
// Take the screenshot from the upper left corner to the right bottom corner.
gfxScreenshot.CopyFromScreen(sc[1].Bounds.X, sc[1].Bounds.Y,
0, 0, sc[1].Bounds.Size, CopyPixelOperation.SourceCopy);
// Save the screenshot to the specified path that the user has chosen.
pictureBoxClient.Image = bmpScreenshot;
}
For closing of form on open of other I am using the code below
formOpen.show();
formClose.Close();
Suggest me how can I save memory usage.
It does, but just your UI objects. It isn't automatic for the variables you use. In an app like this, using big objects that take very little GC heap space but lots of unmanaged resources, the garbage collector doesn't typically run often enough to keep you out of trouble. You have to help and explicitly dispose the objects so you don't leave it up to the GC to take care of the job.
It may take too long for it to start running, you can build up a lot of unmanaged memory usage before it gets to run the finalizers. Potentially crashing your program with OOM, although you are still very far removed from that problem. Right now you are just running "heavy".
Add an event handler for the FormClosed event. You need to call the Dispose() method on the gfxScreenshot and bmpScreenshot objects. And surely those HondaDb objects need some kind of cleanup as well.
Do not assume that will instantly solve memory usage increments, the GC is not eager to release address space back to the operating system. Keeping it around instead with the assumption that you are likely going to have a need for it soon. The proper usage pattern is it stabilizing after a while at a reasonable number, then suddenly dropping and building back up. A saw-tooth pattern. Write a little unit test that calls creates and destroys your form object repeatedly, ensuring that it does the non-trivial jobs of taking the screenshot and accessing the dbase. Now you know with confidence that you don't have a run-away leak problem.
No, when you call Form.Close() you are just telling to close the form. the object is still there in memory and if you have a reference to it, it will be there until you have held that reference.
.NET has automatic garbage collection mechanism which collect objects that are garbage (you have no reference to them and they can not be accessed). So objects are removed from memory when they become garbage and .NET garbage collector starts it works. You can force executing garbage collector by calling GC.Collect().
More about GC
Have a look at this MSDN Thread. It's about dispoable Windows, this should release all ressource held by a an instance of a class. Then the garbage collector should do it's work.

Memory Leak caused by System.Drawing.Internal.GPStream

My application keeps growing in size everytime I open and close a certain Form. I used dotTrace and came up with an ever growing list of object of type System.Drawing.Internal.GPStream which are creating byte arrays continuously without every disposing them. I did some research and found out the .net does not support any means of closing such memory streams. the following
foreach (Type t in Assembly.GetExecutingAssembly().GetTypes())
{
if (t.IsClass && t.BaseType.Name.ToLower() == "form")
{
//Assembly ass = Assembly.GetExecutingAssembly();
object obj = null;
obj = Activator.CreateInstance(t);
Form f = new Form();
f = (Form)obj;
if ((string)f.Tag != "DNI") // Do Not Import
{
DataRow dr = Formsdt.NewRow();
dr["Name"] = f.Name;
dr["Text"] = f.Text;
dr["Tag"] = f.Tag;
Formsdt.Rows.Add(dr);
}
}
}
The intent of this code is to loop over all Forms and retrieve the controls in order to set access rights to users, activating and deactivating controls as needed programmatically.
Any insight is appreciated.
Note that
While( i am opening and closing the form)
==> Memory Allocation keeps on increasing
Somethings not being disposed of properly. Do you have warnings that say X class is iDisposable and you're not disposing it? Look into using 'using' blocks.
See this :
"A FileStream involves unmanaged resources which could actually be
immediately freed upon calling Dispose. A MemoryStream, on the other
hand, stores a managed byte array in its _buffer variable, which is
not freed at disposal time. In fact, the _buffer is not even nulled in
the MemoryStream's Dispose method, which is a SHAMEFUL BUG IMO because
nulling the reference could make the memory eligible for GC right at
disposal time. Instead, a lingering (but disposed) MemoryStream
reference still holds onto memory. Therefore, once you dispose it, you
should also null it if it's still in scope." – Triynko Oct 25 '10 at
20:46
Is a memory leak created if a MemoryStream in .NET is not closed?
Creating Forms in a loop will cause problems, depending the code in it's constructor it can fire events that will choke the message loop. Just to check, try adding an application.doevents in the loop and watch if memory gets released.
Maybe you will need to refactor your classes in order to determine access on a property that is outside a form. Something like:
Class MyObject
Public my_form as Form
Public Tag as string
end class
So you don't need to instantiate a Form.
Regards,
MarianoC.

Please explain Memory Leakage in Managed Code with example?

I was asked this question in an interview: How does memory leakage problem occur in C# as of all know Garbage Collector responsible for all the memory management related work? So how is it possible?
From MSDN:-
A memory leak occurs when memory is allocated in a program and is
never returned to the operating system, even though the program does
not use the memory any longer. The following are the four basic types of memory leaks:
In a manually managed memory environment: Memory is dynamically allocated and referenced by a pointer. The pointer is erased before the memory is freed. After the pointer is erased, the memory can no longer be accessed and therefore cannot be freed.
In a dynamically managed memory environment: Memory is disposed of but never collected, because a reference to the object is still active. Because a reference to the object is still active, the garbage collector never collects that memory. This can occur with a reference that is set by the system or the program.
In a dynamically managed memory environment: The garbage collector can collect and free the memory but never returns it to the operating system. This occurs when the garbage collector cannot move the objects that are still in use to one portion of the memory and free the rest.
In any memory environment: Poor memory management can result when many large objects are declared and never permitted to leave scope. As a result, memory is used and never freed.
Dim DS As DataSet
Dim cn As New SqlClient.SqlConnection("data source=localhost;initial catalog=Northwind;integrated security=SSPI")
cn.Open()
Dim da As New SqlClient.SqlDataAdapter("Select * from Employees", cn)
Dim i As Integer
DS = New DataSet()
For i = 0 To 1000
da.Fill(DS, "Table" + i.ToString)
Next
Although this code is obviously inefficient and not practical, it is meant to demonstrate that if objects are added to a collection (such as adding the tables to the DataSet collection), the objects are kept active as long as the collection remains alive. If a collection is declared at the global level of the program, and objects are declared throughout the program and added to that collection, this means that even though the objects are no longer in scope, the objects remain alive because they are still being referenced.
You may also check this reference:-
Identify And Prevent Memory Leaks In Managed Code
The above link gives a very good conclusion
Although .NET reduces the need for you to be concerned with memory,
you still must pay attention to your application's use of memory to
ensure that it is well-behaved and efficient. Just because an
application is managed doesn't mean you can throw good software
engineering practices out the window and count on the GC to perform
magic.
Just holding on to a reference to an object when you actually don't have any use for it anymore is a good way to leak. Particularly so when you store it in a static variable, that creates a reference that lives for the life of the AppDomain unless you explicitly set it back to null. If such a reference is stored in a collection then you can get a true leak that can crash your program with OOM. Not usual.
Such leaks can be hard to find. Particularly events can be tricky that way, they will get the event source object to add a reference to the event handler object when you subscribe an event handler. Hard to see in C# code because you never explicitly pass this when you subscribe the event. If the event source object lives for a long time then you can get in trouble with all of the subscriber objects staying referenced.
The tricky ones do require a memory profiler to diagnose.
Example would be a Class Child containing ClickEventHandler method subscribed to an Event ClickEvent of another class Parent.
GC of Child class would be blocked until Parent class goes out of scope..Even if Child goes out of scope it won't be collected by GC until Parent goes out of scope
All such subscribers subscribing to a Broadcaster(Event) would not be collected by GC until the broadcaster goes out of scope.
So, its a one way relation
Broadcaster(ClickEvent) -> Subscribers(ClickEventHandler)
GC of all the ClickEventHandlers would be blocked until ClickEvent goes out of scope!
As example:
You have application with main form and static variable Popups[] collectionOfPopups.
Store all application popups objects into static array and never delete them.
So with each new popup will take memory and GC will never release it.
Try to read how GC works
http://msdn.microsoft.com/en-us/library/ee787088.aspx
This will explains everything.
There can be multiple reasons, but here is one:
Consider two classes:
class A
{
private B b;
}
class B
{
private A a;
}
If you create an object for each of those classes, and cross-link them, and after that both those objects go out of the scope, you will still have link to each of them within another one. It is very difficult for GC to catch these sorts of crosslinks, and it may continue to believe that both objects are still in use.

Form.ShowDialog() and dispose

If I have a method like this:
public void Show()
{
Form1 f = new Form1();
f.ShowDialog();
}
Do I still need to call dispose on the form even though it will go out of scope, which will be eligible for garbage collection.
From some testing, calling this Show() multiple times .. at some point it seems like the GC collects it since I can see the memory spiking then it goes down at some point in time.
From MSDN it seems to say you MUST call dispose when the form is not needed anymore.
What tends to happen is if the item has purely managed resources, calling dispose is not necessarily required, but is strongly advised because it makes disposal deterministic. It isn't always required (in a technical sense) because those managed resources would likely themselves now be eligible for GC, or there is actually nothing to dispose by default and it's an extensibility point.
For unmanaged resources, the Dispose Pattern advises implementing a finalizer, which will be called on GC. If types do not implement the finalizer and dispose is not called, then it is possible (well, very likely) that resources would be left unhandled. Finalizers are the last chance offered by the runtime for clearing your stuff up - they are also time-limited.
Note, that it does not make GC or managed memory reclamation deterministic, disposal is not delete from C++. A disposed item could be a long way away from actually being collected. However, in the managed world, you don't care about deterministic collection, only resource management - in other words, disposal.
That said, I always make sure I call Dispose or use a using statement if a type is disposable, regardless of whether it uses managed or unmanaged resources - it is the expected convention:
public void Show()
{
using (var f = new Form1())
{
f.ShowDialog();
} // Disposal, even on exceptions or nested return statements, occurs here.
}
Update:
After a discussion with Servy I feel I have to express this point as the reasoning behind my advice of disposing where possible. In the case of MemoryStream, it is clearly a disposable type, but actually does not dispose of anything currently.
Relying on this, however, is to rely on the implementation of MemoryStream. Were this to change to include an unmanaged resource, this would then mean that a reliance on MemoryStream not having anything to dispose becomes problematic.
Where possible (as is the case with IDisposable) I prefer to rely on the public contract. Working against the contract in this instance would mean I am safe from underlying implementation changes.
Although you rarely have to manually dispose in C# imo, you could try it like this:
public void Show()
{
using (Form1 f = new Form1())
{
f.ShowDialog();
}
}
Then at the last accolade of the using part it will get disposed of automatically.
ShowDialog has side effect of keeping the GDI objects alive. In order to avoid GDI leak we need to dispose the ShowDialog appropriately. Where as Show method does not have any implication and GDI will be released appropriately. It is recommended to dispose the showDialog and do not rely on Garbage collector.
You could simply do:
using (var f = new Form1())
f.ShowDialog();
If you want to explicitly dispose, use
using(Form1 f = new Form1()){
f.ShowDialog();
}
This ensures Dispose() is called, as well as it occurs immediately
In your specific example, no, it's unlikely that it would be particularly useful. Forms do not hold onto a significant amount of resources, so if it takes a little bit longer for some portion of it's code to get cleaned up it isn't going to cause a problem. If that form just happens to be holding onto a control that is used to, say, play a video, then maybe it's actually holding onto some significant number of resources, and if you actually do dispose of those resources in the dispose method then it's worth taking the time to call dispose. For 99% of your forms though, their Dispose method will be empty, and whether you call it or not is unlikely to have any (or any noticeable) effect on your program.
The reason that it's there is primarily to enable the ability to dispose of resources in those 1% of cases where it's important.
It's also worth noting that when a Form is closed its Dispose method is already being called. You would only ever need to add a using or explicit Dispose call if you want to dispose of a Forms resources before that form is closed. (That sounds like a generally bad idea to me). This is easy enough to test. Just create a project with two forms. Have the second form attach an event handler to the Disposing event and show a message box or something. Then when you create an instance of that form and show it (as a dialog or not) you'll see that when you close it the message box will pop up right away, even if you keep the 'Form' instance around and without you ever needing to add a using or Dispose call.
Yes, you need and MUST call Dispose or use using statement, otherwise it can be, that instance remains in memory.
You can check it, if you put a Timer to the form and set a break point in the Timer.Tick handler. Even after closing the form without Dispose the handler will be called.

How to free virtual memory?

I have a crawler application (with C#) that downloads pages from web .
The application take more virtual memory ,
even i dispose every object and even use GC.Collect() .
This , have 10 thread and each thread has a socket that downloads pages .
In each thread , i have a byte[] buffer that store content of page , and have
an string str_content that i store in it , content of page in string .
I have a Sytem.Timer that every 3 second chech , if each thread has been stopped ,
assign it new thread and start it.
I use dispose method and even use GC.Collect() in my application , but in 3 hour my application take
500 MB on virtual memory (500 MB on private bytes in Process explorer) . Then my system
will be hang and i should restart my pc .
would it be rude , If i assign my byte[] and string to null ?
Is there any way that i use to free virtual memory ?
Thanks .
First of all, you SHOULDN'T be calling gc.collect() anyway, as it is a costly call, and shouldn't be necessary.
If you are seeing growth AND you are still calling gc.collect() you have resources that still have references, thus they can't be collected.
I would start looking at your code and making sure that all of your objects are declared at the proper scope, that you are using the Using Statement syntax to ensure that items implementing IDisposable are properly cleaned up and do a full review of your code.
The next step would be to take a tool like ANTS profiler or the like and look at what is actually stored in memory.
It would take exploration of your code to see where your memory leaks are. It's likely in events that you're tying into (either manually or automatically) that cause apparently-out-of-scope objects to not get properly disposed.
In C# (and in Java) as long as you have a reference to the object, the program environment assumes you are still using the object. Calls to free memory will only free unused objects. The key is to stop using the object.
Odds are excellent you have something like:
Object mine = new Object();
the key is that you also need something like:
mine = null;
to signal that the "mine" object is no longer being used. Typically these problems don't happen in code blocks like this because once you leave the block, the variables aren't accessible anymore:
public void process() {
Object mine = new Object();
}
Typically these problems happen in code blocks like this, because the Collection accumulates objects over time:
static List tasks = new ArrayList();
public void process(String item) {
tasks.add(item);
}
The key is that without a corresponding tasks.remove(item) the list will hold references to the items forever thwarting garbage collection efforts.

Categories

Resources