In my C# Winforms App, I have the following (minimal code shown)
Form1 is the main app that the user uses to do stuff. Form2 shows a help file that explains how to use the features on Form1 to do stuff. I want the user to be able to display (modeless) and close the help file at will so long as Form1 is visible.
I also worry about the memory leak that may occur as the user opens and closes Form2. So, when the user closes Form2, it raises an event that Form1 subscribes to. When the Form1 event method is invoked, is calls Dispose() on Form2, sets the Form2 object to null and calls the garbage collector.
Will this remove the chance for a memory leak caused by the user opening and closing Form2? Is it overkill? Is there a better way of ensuring garbage collection at the point in time that Form2 is closed? I don't want to rely on Windows doing it later when it decides to
UPDATE
Jimi pointed out that I don't need a custom event handler for the Form2 Closed event. He's right. In my Form1 class, I'm now using the standard FormClosedEventHandler for my Form2. The code itself, however remains pretty much the same. However, when I remove the call to GC.Collect(), I'm seeing evidence of a memory leak using Task Manager.
Here's my data:
Run #1. Form2_FormClosed method has:
------------------------------------
f_HelpForm.Dispose();
f_HelpForm = null;
GC.Collect();
Start App
Task Manager Memory for app: 6.7 MB
Open and Close Form2 20 times
Task Manager Memory for app: 8.2 MB
Run #2. Form2_FormClosed method has:
------------------------------------
f_HelpForm.Dispose();
f_HelpForm = null;
//GC.Collect();
Start App
Task Manager Memory for app: 6.9 MB
Open and Close Form2 20 times
Task Manager Memory for app: 18.9 MB
Run #3. Form2_FormClosed method has:
------------------------------------
//f_HelpForm.Dispose();
f_HelpForm = null;
//GC.Collect();
Start App
Task Manager Memory for app: 6.9 MB
Open and Close Form2 20 times
Task Manager Memory for app: 18.1 M
Without the call to GC.Collect(), and with or without the call to Dispose(), the footprint grows 100% bigger as compared to the code that includes the call to GC.collect().
I hear what you guys are saying, but .......... I think I'll leave my code in its "Run #1" configuration
The code
Note: I acknowledge that setting form2 = null has a direct influence on behind-the-scenes garbage collection. However, my purpose in setting form2 = null is to provide a signal to the Form2Button_Click
method that it can use to decide whether or not to instantiate a Form2 object
public partial class Form1 : Form
{
Form2 form2;
public Form1()
{
form2 = null;
}
private void Form2Button_Click(object sender, EventArgs e)
{
if (form2 == null)
{
form2 = new ClsHelpForm(this);
form2.Form2Closed = Form2_FormClosed;
}
form2.Select();
form2.Show();
}
//When this user clicks the Help button on Form1, this method is invoked
private void Form2_FormClosed(object sender, EventArgs e)
{
form2.Form2Closed -= Form2_FormClosed;
form2.Dispose();
form2 = null;
GC.Collect();
}
{
public partial class Form2 : Form
{
public event EventHandler Form2Closed;
public Form2()
{
}
//When the user clicks the "X" button on Form2, this method is invoked
private void Form2_FormClosed(object sender, Form2EventArgs e)
{
Form2Closed?.Invoke(this, EventArgs.Empty);
}
}
CodePudding user response:
I also worry about the memory leak that may occur as the user opens and closes Form2.
Why are you worried about a memory leak? Don't try to optimize when there's no evidence of a problem. As long as Form2 and all of its child objects actually clean up resources when Dispose is called, there should be no memory leak.
Is there a better way of ensuring garbage collection at the point in time that Form2 is closed? I don't want to rely on Windows doing it later when it decides to
This seems like unnecessary paranoia. Just be sure Form2 cleans up in its Dispose method and let garbage collection occur naturally. Everything looks fine except remove the GC.Collect() call.
CodePudding user response:
If you put trash in the kitchen garbage can, and 5 minutes later the trash is still there, it does NOT mean that the trash will be there forever. It just means that the trash hasn't been emptied yet. It will get emptied eventually once it gets full enough. A "leak" would be if you put your trash on the floor, in which case it would not get picked up when the trashcan gets full. (not a perfect analogy, since someone is (hopefully) going to pick it up at some point, but you get the idea)
Your observations probably show a 100% growth because there's no memory pressure to require a collection. A memory leak would only occur if that memory never gets freed by the GC, which forcing a garbage collection would not fix. An example of a memory leak would be a reference to an unmanaged resource that is not release when the form is disposed (not closed).
Calling GC.Collect
yourself is not going to fix memory leaks - it just cleans up memory earlier that the system needs to.