HighTechTalks DotNet Forums  

Anonymous delegates and events

Dotnet Framework (CLR) microsoft.public.dotnet.framework.clr


Discuss Anonymous delegates and events in the Dotnet Framework (CLR) forum.



Reply
 
Thread Tools Search this Thread Display Modes
  #1  
Old   
ewolfman
 
Posts: n/a

Default Anonymous delegates and events - 10-09-2006 , 06:36 PM






Hi,

I have a weird situation and I was wondering if anyone can help out.

In my WinForms application, I have several UserControls which contain
other UserControls. Some of the "inner" UserControls raise events,
which are handled by the "parent" UserControls. The event handling is
performed using an anonymous event handler.

Using sos.dll, I discovered that the UserControls (parent and child)
are not elligable for GC, when I'm disposing of the "parent"
UserControl. I'm also making sure that the child's Dispose() is called,
so please read on.

However, if I change the anonymous event handler to a "normal" event
handler, sos.dll reports that the controls are elligable for
collection, and indeed when I invoke GC.Collect (just for the debug
purposes, of course) - they are collected ok.

I wasn't able to reproduce this on a test app.

The following (old) thread describes a similiar hypothetical situation,
but there isn't a clear answer on this:
http://groups.google.com/group/micro...4868e69bb0234a

Thanks.


Reply With Quote
  #2  
Old   
Chris Mullins
 
Posts: n/a

Default Re: Anonymous delegates and events - 10-09-2006 , 07:46 PM






I've tracked down a number of memory management issues that resovled to
event handler hooks that weren't being cleaned up.

Anytime something has a hook into one of your events, you're entire object
is considered still rooted and thus not eligible for
GC. Being disposed or not disposed didn't really make any difference.

I know this doesn't quite answer your question, but just make sure to
explicitly clear out all your event handlers. In VB this is easy - the
'withevents' stuff takes care of it for you. In C# it takes explicit code.
Anytime you have a "+=" you need to have a "-=" as well. If not, you're
going to be leaking memory.

If you're using SOS, it sounds like you have things under control, debugging
wise. The tool I had the most success tracking this stuff down with was the
SciTech memory profiler. You're already past the "tracking it down" phase
though...

--
Chris Mullins, MCSD.NET, MCPD:Enterprise
http://www.coversant.net/blogs/cmullins

"ewolfman" <ewolfman (AT) yahoo (DOT) com> wrote

Quote:
Hi,

I have a weird situation and I was wondering if anyone can help out.

In my WinForms application, I have several UserControls which contain
other UserControls. Some of the "inner" UserControls raise events,
which are handled by the "parent" UserControls. The event handling is
performed using an anonymous event handler.

Using sos.dll, I discovered that the UserControls (parent and child)
are not elligable for GC, when I'm disposing of the "parent"
UserControl. I'm also making sure that the child's Dispose() is called,
so please read on.

However, if I change the anonymous event handler to a "normal" event
handler, sos.dll reports that the controls are elligable for
collection, and indeed when I invoke GC.Collect (just for the debug
purposes, of course) - they are collected ok.

I wasn't able to reproduce this on a test app.

The following (old) thread describes a similiar hypothetical situation,
but there isn't a clear answer on this:
http://groups.google.com/group/micro...4868e69bb0234a

Thanks.




Reply With Quote
  #3  
Old   
ewolfman
 
Posts: n/a

Default Re: Anonymous delegates and events - 10-09-2006 , 07:49 PM



I have more to add to my original post.

When using an anonymous delegate as an event handler, and using the
add/remove accessors to register the event on an EventHandlerList, I
observe (what is expected) that the original anonymous event handler is
NOT removed from the list.

This confirms what troubled me: using '-=' with an anonymous delegate,
is worthless. If this is true, then using anonymous delegates as Event
Handlers is a very risky business! They remain "forever" in the
EventHandlerList/multicast-delegate's invocation list and do not allow
GC on the referenced object (until the "child" UserControl is collected
itself).

But what puzzles me still, is the fact that I could not reproduce this
error. From this I gather that the "child" UserControl, in the
"reproducing code" (which contains the EventHandlerList) has been
cleared for GC, and therefore the "parent" has also been cleared for
GC. This *is* the expected behaviour as far as I'm concerned. So back
to my original post - why is my application behaving weird with
anonymous Event Handlers?


Reply With Quote
  #4  
Old   
ewolfman
 
Posts: n/a

Default Re: Anonymous delegates and events - 10-09-2006 , 07:56 PM



Hi Chris, thanks for your reply.

I forgot to mention, that *I am* using the '-=' operator. If you'll
read my other "additions" post (posted AFTER you have posted your
reply...), then you'll see my thoughts regarding anonymous delegates
and removing the delegate from the EventHandlerList/Invocation List.

I've mentioned the Dispose, just in case someone would have replied
'use Dispose()'...

Once again, just to make sure: using the '-=' operator on a
'non-anonymous' event handler works great. It is the anonymous event
handler which makes all the trouble. And again - in my "additions" post
you can see that I wasn't able to reproduce this on a test application,
using anonymous delegates. This is what's so weird about it.


Reply With Quote
  #5  
Old   
Jon Shemitz
 
Posts: n/a

Default Re: Anonymous delegates and events - 10-09-2006 , 10:57 PM



ewolfman wrote:

Quote:
why is my application behaving weird with
anonymous Event Handlers?
My guess is that sometimes you are explicitly saving the event
handler, and sometimes you are not.

Code like

// subscribe
EventDelegate Registered = new EventDelegate(validMethod);
Event += Registered;

// cancel, as in IDispose.Dispose
Event Event -= Registered;

will work with delegates to named methods. It's not necessary, though.
You can just code

// subscribe
Event += new EventDelegate(validMethod);
// or "Event += validMethod", in 2

// cancel, as in IDispose.Dispose
Event Event -= new EventDelegate(validMethod);

The -= doesn't care about delegate reference equality. It just matches
instance reference and method reference. If (all) match, the delegate
is removed. But with anonymous methods,

// subscribe
Event += delegate
{
// whatever
};

// cancel, as in IDispose.Dispose
Event Event -= delegate
{
// it doesn't help if you replicate the code exactly!
};

is pointing to different code. Does

// subscribe
EventDelegate Registered = delegate
{
// whatever
};
Event += Registered;

// cancel, as in IDispose.Dispose
Event Event -= Registered;

work for you?

--

..NET 2.0 for Delphi Programmers www.midnightbeach.com/.net
Delphi skills make .NET easy to learn Great reviews & good sales.


Reply With Quote
  #6  
Old   
Jon Skeet [C# MVP]
 
Posts: n/a

Default Re: Anonymous delegates and events - 10-10-2006 , 02:19 AM



ewolfman <ewolfman (AT) yahoo (DOT) com> wrote:
Quote:
I have more to add to my original post.

When using an anonymous delegate as an event handler, and using the
add/remove accessors to register the event on an EventHandlerList, I
observe (what is expected) that the original anonymous event handler is
NOT removed from the list.

This confirms what troubled me: using '-=' with an anonymous delegate,
is worthless. If this is true, then using anonymous delegates as Event
Handlers is a very risky business! They remain "forever" in the
EventHandlerList/multicast-delegate's invocation list and do not allow
GC on the referenced object (until the "child" UserControl is collected
itself).
They're only useless in the situations where you *need* to remove event
handlers. Most of the time when I write event handlers, the object
"owning" the event becomes eligible for garbage collection at the same
logical time as the target of the event handler, so it's not an issue.

--
Jon Skeet - <skeet (AT) pobox (DOT) com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too


Reply With Quote
  #7  
Old   
ewolfman
 
Posts: n/a

Default Re: Anonymous delegates and events - 10-10-2006 , 04:15 AM



Quote:
They're only useless in the situations where you *need* to remove event
handlers. Most of the time when I write event handlers, the object
"owning" the event becomes eligible for garbage collection at the same
logical time as the target of the event handler, so it's not an issue.
Correct. I was "generalizing".

I have a question:
If both "parent" and "child" are not referenced by anyone, except for
the child containing the reference to the anonymous delegate in the
"parent", aren't they supposed to be eligible for GC?

This is what I expect it to be, and this is what my "reproducing code"
behaves like. It's possible that I'm making a wrong assumption
regarding my application, that when I replace the anonymous delegate to
a non-anonymous delegate, they both become eligible for GC. But then
again, it seems to be a fact.

Any ideas?



Reply With Quote
  #8  
Old   
ewolfman
 
Posts: n/a

Default Re: Anonymous delegates and events - 10-10-2006 , 04:57 AM



Hi Jon, thanks for your reply.

Quote:
My guess is that sometimes you are explicitly saving the event
handler, and sometimes you are not.
It's possible, althought I can't think of a way to tell if this is
true.

Quote:
The -= doesn't care about delegate reference equality. It just matches
instance reference and method reference. If (all) match, the delegate
is removed. But with anonymous methods,
True.


Quote:
// subscribe
Event += delegate
{
// whatever
};

// cancel, as in IDispose.Dispose
Event Event -= delegate
{
// it doesn't help if you replicate the code exactly!
};
Correct again.

Quote:
is pointing to different code. Does

// subscribe
EventDelegate Registered = delegate
{
// whatever
};
Event += Registered;

// cancel, as in IDispose.Dispose
Event Event -= Registered;

work for you?
No, it doesn't, as I've written earlier:
"When using an anonymous delegate as an event handler, and using the
add/remove accessors to register the event on an EventHandlerList, I
observe (what is expected) that the original anonymous event handler is
NOT removed from the list.

This confirms what troubled me: using '-=' with an anonymous delegate,
is worthless". (Regarding to Jon Skeet's remark, this comment is
"generalizing", so please note that I'm addressing a particular
situation).

Please read my question, in my reply to Jon Skeet. I'll be happy if you
have further comments.



Reply With Quote
  #9  
Old   
Chris Mullins
 
Posts: n/a

Default Re: Anonymous delegates and events - 10-10-2006 , 12:33 PM



Is the class you're attaching an event to your own class?

If so, it would be interesting to have some trace code in the add/remove
handlers for the events.

The only other thing I can think of is that you have some strange race
condition that is, once-in-a-while, causing your code to remain rooted. This
would explain the "cannot duplicate" part of the problem. What does the code
in the anonymous mehtod look like?


--
Chris Mullins

"ewolfman" <ewolfman (AT) yahoo (DOT) com> wrote

Quote:
Hi Chris, thanks for your reply.

I forgot to mention, that *I am* using the '-=' operator. If you'll
read my other "additions" post (posted AFTER you have posted your
reply...), then you'll see my thoughts regarding anonymous delegates
and removing the delegate from the EventHandlerList/Invocation List.

I've mentioned the Dispose, just in case someone would have replied
'use Dispose()'...

Once again, just to make sure: using the '-=' operator on a
'non-anonymous' event handler works great. It is the anonymous event
handler which makes all the trouble. And again - in my "additions" post
you can see that I wasn't able to reproduce this on a test application,
using anonymous delegates. This is what's so weird about it.




Reply With Quote
  #10  
Old   
Ben Voigt
 
Posts: n/a

Default Re: Anonymous delegates and events - 10-10-2006 , 02:44 PM



"ewolfman" <ewolfman (AT) yahoo (DOT) com> wrote

Quote:
They're only useless in the situations where you *need* to remove event
handlers. Most of the time when I write event handlers, the object
"owning" the event becomes eligible for garbage collection at the same
logical time as the target of the event handler, so it's not an issue.

Correct. I was "generalizing".

I have a question:
If both "parent" and "child" are not referenced by anyone, except for
the child containing the reference to the anonymous delegate in the
"parent", aren't they supposed to be eligible for GC?

This is what I expect it to be, and this is what my "reproducing code"
behaves like. It's possible that I'm making a wrong assumption
regarding my application, that when I replace the anonymous delegate to
a non-anonymous delegate, they both become eligible for GC. But then
again, it seems to be a fact.

Any ideas?

If you are accurately describing the situation, that would be a bug. If
object A registers a closure (anonymous delegate using "this" pointer) on
object B's event, then object B has a reference to object A that you may not
be able to get rid of easily. But that should not prevent the system "A+B"
from being unreachable from roots and therefore collectable.




Reply With Quote
Reply




Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off



Powered by vBulletin Version 3.5.4
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.