views:

238

answers:

3

If I do the following:

public class Test
{
 public static void Main()
 {
  List<Person> persons = new List<Person> { new Person() };

  persons[0].Sneezing += new EventHandler(Person_Sneezing);

  persons = null;
 }

 public static void Person_Sneezing(object sender, EventArgs e)
 {
  (sender as Person).CoverFace();
 }
}

Does the person that was in person[0] still exists in memory because it's Sneezing delegate has a reference to the Person_Sneezing method or does it get collected by the GC?

+6  A: 

This will be collected by the GC. To be kept in memory an object must be referenced directly or indirectly by ...

  1. A value on the stack
  2. A value rooted in a strong GC handle
  3. A corner case or two I'm not thinking of at the moment

This is not true for the object at persons[0]. So it will be collected.

That is of course assuming the constructor for Person() doesn't do anything funny like add itself to ThreadLocalStorage.

JaredPar
A: 

Further to the answers you've already got, you need to be careful in more realistic examples.

If your application has a main window that survives as long as the program runs, and you frequently create "short-lived" objects that enlist their methods to events on the main window, then you must delist the objects from those events when you no longer need them, because otherwise those objects won't be "short-lived" at all - they'll survive as long as the main window, i.e. until the user closes the application. The effective result will be equivalent to a memory leak.

It can help if you make the short-lived object's class implement IDisposable, so you can delist from the events in Dispose, and then make sure you call dispose when you want to discard an object.

Daniel Earwicker
+5  A: 

You're halfway there; this would be a memory leak if it were the other way around. That is, if it looked like this:

public class Test
{
    public void HookupStuff()
    {
        List<Person> persons = new List<Person> { new Person() };

        this.EventHappened += new EventHandler(persons[0].SomeMethod);
        // persons[0].Sneezing += new EventHandler(Person_Sneezing);

        persons = null;
    }
}

Now persons[0] will stick around, even though you nulled out persons, since the parent class has a reference to a method on it.

mquander
Would you call it a leak? If Test goes way so does persons[0].
Matt Spradley
Sure, but everything goes away *eventually* -- at worst, it'll all go away when your application exits! I'd call it a leak when it doesn't go away when you think it's going to go away.
mquander
(Also, if you didn't make another reference to persons[0], you'll be hard-pressed to ever get it back, so it's basically leaked into nothingness.)
mquander
For an example of how this can become a leak, destroy a ToolStrip that's displayed on a form without setting Visible to false first. You'll find (if you use a memory profiler) that it's still there - because Windows raises an event notifying all themed controls when the theme is changed, and to do that it maintains a reference to the ToolStrip. (If you think about this a bit, you'll figure out why I know this. Hint: I didn't *want* to know it.)
Robert Rossney