Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsFree MagazinesWhite PapersSubmit Content
Discussion GroupsASP.NETWindows FormsLanguages.NET FrameworkVisual Studio.NET
Articles.NET FrameworkASP.NETToolsWindows Forms
.NET DirectoryOpen Source ProjectsUser GroupsWeb Resources
Related Topics
Visual Basic 6SQL ServerMS AccessOther DB ProductsMS Server ProductsMore Topics ...

.NET Forum / .NET Framework / CLR / October 2006

Tip: Looking for answers? Try searching our database.

Anonymous delegates and events

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
ewolfman - 09 Oct 2006 23:36 GMT
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/microsoft.public.dotnet.framework.clr/browse_frm/
thread/4583fa08a8cfc96a/974868e69bb0234a?lnk=st&q=anonymous+delegates+and+events
&rnum=4#974868e69bb0234a


Thanks.
Chris Mullins - 10 Oct 2006 00:46 GMT
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...

Signature

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

> Hi,
>
[quoted text clipped - 22 lines]
>
> Thanks.
ewolfman - 10 Oct 2006 00:56 GMT
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.
Chris Mullins - 10 Oct 2006 17:33 GMT
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?

Signature

Chris Mullins

> Hi Chris, thanks for your reply.
>
[quoted text clipped - 11 lines]
> 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.
ewolfman - 10 Oct 2006 00:49 GMT
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?
Jon Shemitz - 10 Oct 2006 03:57 GMT
> 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?

Signature

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

ewolfman - 10 Oct 2006 09:57 GMT
Hi Jon, thanks for your reply.

> 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.

> 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.

>   // subscribe
>   Event += delegate
[quoted text clipped - 7 lines]
>     // it doesn't help if you replicate the code exactly!
>   };

Correct again.

> is pointing to different code. Does
>
[quoted text clipped - 9 lines]
>
> 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.
Jon Skeet [C# MVP] - 10 Oct 2006 07:19 GMT
> I have more to add to my original post.
>
[quoted text clipped - 9 lines]
> 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.

Signature

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

ewolfman - 10 Oct 2006 09:15 GMT
> 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?
Ben Voigt - 10 Oct 2006 19:44 GMT
>> 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
[quoted text clipped - 15 lines]
>
> 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.

Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.