Memory Leak in C# 2.0 W/ Anonymous Delegates?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • anonymous

    Memory Leak in C# 2.0 W/ Anonymous Delegates?

    I believe I ran into an interesting way to create memory leaks in C# 2.0
    using anymous delegates. Here is a sample of the code in question.

    private void Handle_Event(ob ject sender, EventArgs e)
    {
    Timer timer = new Timer();
    timer.Interval = 10000;
    NotifyForm notifyForm = new notifyForm();
    notifyForm.Show ();
    timer.Tick += delegate(object timerSender, EventArgs tArgs)
    {
    notifyForm.Clos e();
    notifyForm.Disp ose();
    timer.Stop();
    };
    timer.Start();
    }

    The above code is responding to an event, displaying a Form to notify the
    user of the completed event and closing the Form in 10 seconds. The
    potential issue I see is I assign an anonymous delegate into the timer's Tick
    event. The timer's Tick event now has a reference to my anonymous delegate.
    According to Anders Heilsbergs book on C# 2.0 the timer reference will now be
    captured and will not be released until after the anonymous delegate has been
    garbage collected, but in the above example the anonymous delegate cannot be
    collected , because the Timer's Tick event has a reference to it. Is this
    analysis of this code correct? If so what suggestions do you have to get
    around this. I have my own suggestion, it goes something this (I really have
    to credit my co-worker Mike for this suggestion):

    private void Handle_Event(ob ject sender, EventArgs e)
    {
    Timer timer = new Timer();
    timer.Interval = 10000;
    NotifyForm notifyForm = new notifyForm();
    notifyForm.Show ();
    //Initializing the handler variable to null allows it to be accessed
    inside of the
    //anonymous delegate.
    EventHandler handler = null;
    handler = delegate(object timerSender, EventArgs tArgs)
    {
    notifyForm.Clos e();
    notifyForm.Disp ose();
    timer.Stop();
    timer.Tick -= handler;
    } ;
    timer.Tick += handler;
    timer.Start();
    }

    The idea in the above example being that the anonymous delegate is assigned
    into a local variable which can be accessed inside of the anonymous delegate.
    By doing this I can unsubscribe from the Tick event allowing the delegate to
    garbage collected, and consequently the Timer instance can also be garbage
    collected. Does this solve the issues of the memory leak? Is there a better
    way to solve this issue? Thank you.



  • Daniel O'Connell [C# MVP]

    #2
    Re: Memory Leak in C# 2.0 W/ Anonymous Delegates?


    "anonymous" <anonymous@disc ussions.microso ft.com> wrote in message
    news:2489C2A5-6815-4288-9893-D76CDB773B9F@mi crosoft.com...[color=blue]
    >I believe I ran into an interesting way to create memory leaks in C# 2.0
    > using anymous delegates. Here is a sample of the code in question.
    >
    > private void Handle_Event(ob ject sender, EventArgs e)
    > {
    > Timer timer = new Timer();
    > timer.Interval = 10000;
    > NotifyForm notifyForm = new notifyForm();
    > notifyForm.Show ();
    > timer.Tick += delegate(object timerSender, EventArgs tArgs)
    > {
    > notifyForm.Clos e();
    > notifyForm.Disp ose();
    > timer.Stop();
    > };
    > timer.Start();
    > }
    >
    > The above code is responding to an event, displaying a Form to notify the
    > user of the completed event and closing the Form in 10 seconds. The
    > potential issue I see is I assign an anonymous delegate into the timer's
    > Tick
    > event. The timer's Tick event now has a reference to my anonymous
    > delegate.
    > According to Anders Heilsbergs book on C# 2.0 the timer reference will now
    > be
    > captured and will not be released until after the anonymous delegate has
    > been
    > garbage collected, but in the above example the anonymous delegate cannot
    > be
    > collected , because the Timer's Tick event has a reference to it. Is this
    > analysis of this code correct? If so what suggestions do you have to get
    > around this. I have my own suggestion, it goes something this (I really
    > have
    > to credit my co-worker Mike for this suggestion):
    >[/color]
    This should collect just fine, since once the anonymous delegate is
    unreferenced and it contains the only reference to the timer, then the timer
    instance cannot be reached from a root and is therefore collectable as well.


    Comment

    • anonymous

      #3
      Re: Memory Leak in C# 2.0 W/ Anonymous Delegates?



      "Daniel O'Connell [C# MVP]" wrote:
      [color=blue]
      >
      > "anonymous" <anonymous@disc ussions.microso ft.com> wrote in message
      > news:2489C2A5-6815-4288-9893-D76CDB773B9F@mi crosoft.com...[color=green]
      > >I believe I ran into an interesting way to create memory leaks in C# 2.0
      > > using anymous delegates. Here is a sample of the code in question.
      > >
      > > private void Handle_Event(ob ject sender, EventArgs e)
      > > {
      > > Timer timer = new Timer();
      > > timer.Interval = 10000;
      > > NotifyForm notifyForm = new notifyForm();
      > > notifyForm.Show ();
      > > timer.Tick += delegate(object timerSender, EventArgs tArgs)
      > > {
      > > notifyForm.Clos e();
      > > notifyForm.Disp ose();
      > > timer.Stop();
      > > };
      > > timer.Start();
      > > }
      > >
      > > The above code is responding to an event, displaying a Form to notify the
      > > user of the completed event and closing the Form in 10 seconds. The
      > > potential issue I see is I assign an anonymous delegate into the timer's
      > > Tick
      > > event. The timer's Tick event now has a reference to my anonymous
      > > delegate.
      > > According to Anders Heilsbergs book on C# 2.0 the timer reference will now
      > > be
      > > captured and will not be released until after the anonymous delegate has
      > > been
      > > garbage collected, but in the above example the anonymous delegate cannot
      > > be
      > > collected , because the Timer's Tick event has a reference to it. Is this
      > > analysis of this code correct? If so what suggestions do you have to get
      > > around this. I have my own suggestion, it goes something this (I really
      > > have
      > > to credit my co-worker Mike for this suggestion):
      > >[/color]
      > This should collect just fine, since once the anonymous delegate is
      > unreferenced and it contains the only reference to the timer, then the timer
      > instance cannot be reached from a root and is therefore collectable as well.
      >
      >
      >[/color]
      You're saying that the original snippet will work just fine? If that's the
      case then don't I run the risk of the timer and the delegate being garbaged
      collected before the Tick event is fired, making it so my notify form remains
      opened indefinately?

      Comment

      • anonymous

        #4
        Re: Memory Leak in C# 2.0 W/ Anonymous Delegates?



        "anonymous" wrote:
        [color=blue]
        >
        >
        > "Daniel O'Connell [C# MVP]" wrote:
        >[color=green]
        > >
        > > "anonymous" <anonymous@disc ussions.microso ft.com> wrote in message
        > > news:2489C2A5-6815-4288-9893-D76CDB773B9F@mi crosoft.com...[color=darkred]
        > > >I believe I ran into an interesting way to create memory leaks in C# 2.0
        > > > using anymous delegates. Here is a sample of the code in question.
        > > >
        > > > private void Handle_Event(ob ject sender, EventArgs e)
        > > > {
        > > > Timer timer = new Timer();
        > > > timer.Interval = 10000;
        > > > NotifyForm notifyForm = new notifyForm();
        > > > notifyForm.Show ();
        > > > timer.Tick += delegate(object timerSender, EventArgs tArgs)
        > > > {
        > > > notifyForm.Clos e();
        > > > notifyForm.Disp ose();
        > > > timer.Stop();
        > > > };
        > > > timer.Start();
        > > > }
        > > >
        > > > The above code is responding to an event, displaying a Form to notify the
        > > > user of the completed event and closing the Form in 10 seconds. The
        > > > potential issue I see is I assign an anonymous delegate into the timer's
        > > > Tick
        > > > event. The timer's Tick event now has a reference to my anonymous
        > > > delegate.
        > > > According to Anders Heilsbergs book on C# 2.0 the timer reference will now
        > > > be
        > > > captured and will not be released until after the anonymous delegate has
        > > > been
        > > > garbage collected, but in the above example the anonymous delegate cannot
        > > > be
        > > > collected , because the Timer's Tick event has a reference to it. Is this
        > > > analysis of this code correct? If so what suggestions do you have to get
        > > > around this. I have my own suggestion, it goes something this (I really
        > > > have
        > > > to credit my co-worker Mike for this suggestion):
        > > >[/color]
        > > This should collect just fine, since once the anonymous delegate is
        > > unreferenced and it contains the only reference to the timer, then the timer
        > > instance cannot be reached from a root and is therefore collectable as well.
        > >
        > >
        > >[/color]
        > You're saying that the original snippet will work just fine? If that's the
        > case then don't I run the risk of the timer and the delegate being garbaged
        > collected before the Tick event is fired, making it so my notify form remains
        > opened indefinately?[/color]
        Well I peeked at the MSIL that is generated and I think I see what you're
        saying. In the original snippet the timer is eligible for garbage
        collection. This means that I run a serious risk of both my timer and
        anonymous delegate getting garbage collected prior to the event even being
        fired. The solution is to make the timer a class level member variable, not
        a local variable. The reason for this is C# generates a nested class for the
        anymous delegate that stores all of the referenced locals. The nested class
        contains a method that has the actual implementation for the anonymous
        delegate logic. That method is assigned in as a delegate to the Tick event.
        Now I've got the timer referencing the instance of my anonymous delegate
        nested class and the anonymous delegate instance reference the timer, but
        they aren't reference by anyone else, making them eligible for garbage
        collection.

        Comment

        Working...