.NET Forum / .NET Framework / New Users / July 2005
References problem
|
|
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 MagazinesGet 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 ...
|
|
|