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 / New Users / July 2005

Tip: Looking for answers? Try searching our database.

References problem

Thread view: 
Enable EMail Alerts  Start New Thread
Thread rating: 
Michal Talaga - 28 Jun 2005 20:26 GMT
Hello!

In windows forms application I have an object MyObject with an event
SomeEvent.
I pass this object to a form to display its data. In this form I attach an
event hadler for SomeEvent.
Now, I close the first form and then the form goes out of scope, and pass
MyObject to some other form, which also attaches handler to SomeEvent.

Now the problem is, even if the first form is closed/deleted (not hidden),
it will not be garbage collected, because of the reference from MyObject
(through the event handler).

Is there a better way to solve this problem, other than manually removing
event handlers from MyObject.SomeEvent when closing the form?
It is of course a bigger problem than the situation described and having to
remember to remove hadlers from events is error prone.

Any advice? I have a feeling that I'm missing something.

Signature

Michal

Rodger Constandse - 28 Jun 2005 21:29 GMT
Hi,

The problem is worse than that, because the first form gets disposed when you
close it, but its event handler still gets called when you fire SomeEvent. If
you try to do anything with that form from the event handler, you will get
exceptions unless you check for it being disposed.

As a rule, I always unhook events in the Dispose method for forms to avoid this
problem. Like you say, it is error prone to have to remember to do this.
Unfortunately, I haven't found any better solutions.

Best regards,

Rodger

Sequence Diagram Editor - Draw sequence diagrams faster
<http://www.SequenceDiagramEditor.com>

> Hello!
>
[quoted text clipped - 15 lines]
>
> Any advice? I have a feeling that I'm missing something.
Lloyd Dupont - 29 Jun 2005 02:36 GMT
congratulation!
you just discover the "memory leak" still in .NET (even though it's garbage
collected).

fortunately there is a very simple fix. unfortunately manual and sometimes
difficult to write.

you should use disposable object (such as Form),
override Dispose()
where you unregister for all (external) event you are listeneing for

When you think of it, that's a difficult issue, that garbage collection
cannot fix, so you have to be carefull with event....
and always unregister properly, when appropriate, by using a IDispose &
Dispose() semantic

> Hello!
>
[quoted text clipped - 15 lines]
>
> Any advice? I have a feeling that I'm missing something.
Nick Malik [Microsoft] - 29 Jun 2005 16:37 GMT
Hardly a memory leak.  This is, as the OP suggested, a reference problem.
The GC can hardly be expected to recycle an object where all references
weren't disposed.

The override of the Dispose method that you suggest is not a workaround...
it is the expectation.  It is normal and expected that a developer who
creates references to an object will be responsible for cleaning them up.

That said, I wonder if the problem isn't easier to handle by seperating the
connection to the UI from the business object itself.

In other words, the object that presents the event should be a seperate
object from the one that holds the data.  When the form closes, the object
can be disposed of as well, thus dropping all references to the form.  This
is a little more in keeping with the notion of Model-View-Controller in that
each object can have an object-level controller that ties the model to the
view.  When the view is disposed, the controller can be tossed and a new one
created for a new view.

Therefore,
when a data item is created, add it to a singleton list where it can be
retrieved.

when a form is opened...
  create a new controller for the data item
  pass a reference to the data item into the controller
  attach the event handler for the controller to the form.

when a form is closed, dispose of the controller as well.
  The controller will drop and therefore, the reference to the form will
drop as well.  However, the data will not be dropped because the singleton
list still points to it.

HTH,

Signature

--- Nick Malik [Microsoft]
   MCSD, CFPS, Certified Scrummaster
   http://blogs.msdn.com/nickmalik

Disclaimer: Opinions expressed in this forum are my own, and not
representative of my employer.
  I do not answer questions on behalf of my employer.  I'm just a
programmer helping programmers.
--

> congratulation!
> you just discover the "memory leak" still in .NET (even though it's
[quoted text clipped - 31 lines]
>>
>> Any advice? I have a feeling that I'm missing something.
Michal Talaga - 29 Jun 2005 19:28 GMT
> Hardly a memory leak.  This is, as the OP suggested, a reference problem.
> The GC can hardly be expected to recycle an object where all references
> weren't disposed.

I have read some articles about this problem and I'm wondering why event
hadlers are not implemented as weak references?
This would solve a great deal of problems, wouldn't it?
I'm wondering how Java guys solved this problem, because I don't know Java
but I suppose that they have also encountered similar situation with their
observer pattern?

> The override of the Dispose method that you suggest is not a workaround...
> it is the expectation.  It is normal and expected that a developer who
> creates references to an object will be responsible for cleaning them up.

It is like in not so old days when developer who created an object (new())
was responsible for deleting it (delete()). It wasn't good and probably that
is why most of us are here in the first place. :-)
Now it isn't that bad as in VB6 when parent->child->parent references
existed, although it is not perfect, having to remember to clean for
yourself. Especialy with all this talk about automatic memory management
etc.
I'll bet that most of the developers aren't even aware of this problem!

> That said, I wonder if the problem isn't easier to handle by seperating
> the connection to the UI from the business object itself.

No, it isn't as far as I know. There can be a situation when one (short
lived) business object listens for events of another (long lived) business
object.
No controler here I suppose, so nothing to dispose other than manualy
removing event handlers.

Signature

Michal

Lloyd Dupont - 29 Jun 2005 23:54 GMT
tss... Nick Malik...
so it's not a memory leak, it's a reference problem..!!
hehehe that's a good one!

call it the way you want, the fact is many people have GUI which register event to data and there is nowhere near enough education in the documentation wich state: "when you dispose your form, unregister to all event you listen"

so people think: managed environment! and forget to unregister!

so let's being diplomatic.
there is a lot of reference problem around (where the application takes more memory than they should but beware, it's not a memory leak said Nick Malik) and there are very little or no education regarding that.

I don't say it's incorrect, as you point out (and I did too!!) that's correct behavior. but the correct behavior to release this memory (to you use your terminology which banned the 'work around' word) is to unregister event in dispose.

Unfortunately it's not advertized enough (*).

It tooks me one year to realize it, and nowehere I was adviced about such a possibility.
To say the least, it's a bug  (sorry, a miss in Nick's language) in the documentation.

(*): Dispose() IS advertized enough, about native reference. But nowhere enough there is mention of event listener
Michal Talaga - 11 Jul 2005 16:24 GMT
> (*): Dispose() IS advertized enough, about native reference. But nowhere
> enough there
> is mention of event listener.

I've just read part of Applied Microsoft .NET Programming by Jeffrey
Richter, where the author mentions about necessity to remove event handler
when it no longer needs to listen for events.

Funny, of all books I've read about .NET, this is the first one that
includes information about this issue.

Signature

Michal

Alvin Bruney [MVP - ASP.NET] - 12 Jul 2005 02:17 GMT
> Funny, of all books I've read about .NET, this is the first one that
> includes information about this issue.
richter's book is well done. he has a lot of experience and it shows. he
also has a nack for explaining difficult topics

Signature

Regards,
Alvin Bruney - ASP.NET MVP

[Shameless Author Plug]
The Microsoft Office Web Components Black Book with .NET
Now available @ www.lulu.com/owc, Amazon.com etc

>> (*): Dispose() IS advertized enough, about native reference. But nowhere
>> enough there
[quoted text clipped - 6 lines]
> Funny, of all books I've read about .NET, this is the first one that
> includes information about this issue.
Lloyd Dupont - 18 Jul 2005 10:43 GMT
just take a look at these 2 java examples (required Java install on your
computer):

http://java.sun.com/docs/books/tutorialJWS/uiswing/components/example-1dot4/Text
ComponentDemo.jnlp

http://java.sun.com/docs/books/tutorialJWS/uiswing/components/example-1dot4/Text
SamplerDemo.jnlp


see how simple they are, see how simple it's to track userr changes, embed a
Java control in your text or protect part of your text.

Now go do the same thing in C# (with RichTextBox?)
When you'll have tell me, do you still think WinForm is great?

just for your information have a quick look to
http://java.sun.com/docs/books/tutorial/uiswing/components/components.html

and follow the tutorial for ScrollPane, Table & Tree.
That might gives you some ideas....
Clive Tong - 29 Jun 2005 11:30 GMT
> Hello!
>
[quoted text clipped - 8 lines]
> it will not be garbage collected, because of the reference from MyObject
> (through the event handler).

Various weak delegates have been talked about on blogs. See, for example,
 http://blogs.msdn.com/greg_schechter/archive/2004/05/27/143605.aspx
Lloyd Dupont - 30 Jun 2005 12:58 GMT
nice paper!!

> Various weak delegates have been talked about on blogs. See, for example,
>  http://blogs.msdn.com/greg_schechter/archive/2004/05/27/143605.aspx
Lloyd Dupont - 30 Jun 2005 13:12 GMT
I just write a simplified class according to their idea ;)

public abstract class WeakContainer<T> : WeakReference
{
   public WeakContainer(object target, EventHandler<T> _delegate)
       : base(_delegate)
   {}

   public void EventHandler(object sender, T eventArgs)
   {
       EventHandler<T> eh = (EventHandler<T>)Target;
       if (eh != null)
           eh(sender, eventArgs);
       else
           Unregister(sender);
   }

   /// <summary>
   /// unregister from the event here
   /// </summary>
   /// <param name="sender">the object sending the event</param>
   abstract void Unregister(object sender);
}
Lloyd Dupont - 30 Jun 2005 13:15 GMT
here is a correct version of a nice, leaner implementation (the previous one didn't compile, hum ... )

public abstract class WeakContainer<T> : WeakReference where T : EventArgs
{
   public WeakContainer(object target, EventHandler<T> _delegate)
       : base(_delegate)
   {
   }

   public void EventHandler(object sender, T eventArgs)
   {
       EventHandler<T> eh = (EventHandler<T>)Target;
       if (eh != null)
           eh(sender, eventArgs);
       else
           Unregister(sender);
   }

   /// <summary>
   /// unregister from the event here
   /// </summary>
   /// <param name="sender">the object sending the event</param>
   public abstract void Unregister(object sender);
}
Lloyd Dupont - 01 Jul 2005 04:17 GMT
after testing I realize you  better write one such object for every type pf target & event.
because, in this case, no one refere the delegate anymore, usually...

 here is a correct version of a nice, leaner implementation (the previous one didn't compile, hum ... )

 public abstract class WeakContainer<T> : WeakReference where T : EventArgs
 {
     public WeakContainer(object target, EventHandler<T> _delegate)
         : base(_delegate)
     {
     }

     public void EventHandler(object sender, T eventArgs)
     {
         EventHandler<T> eh = (EventHandler<T>)Target;
         if (eh != null)
             eh(sender, eventArgs);
         else
             Unregister(sender);
     }

     /// <summary>
     /// unregister from the event here
     /// </summary>
     /// <param name="sender">the object sending the event</param>
     public abstract void Unregister(object sender);
 }

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.