References problem

M

Michal Talaga

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

Rodger Constandse

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

Lloyd Dupont

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
 
C

Clive Tong

Michal Talaga said:
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).

Various weak delegates have been talked about on blogs. See, for example,
http://blogs.msdn.com/greg_schechter/archive/2004/05/27/143605.aspx
 
N

Nick Malik [Microsoft]

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,

--
--- 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.
--
Lloyd Dupont said:
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
 
M

Michal Talaga

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

Lloyd Dupont

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

Lloyd Dupont

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);
}
 
L

Lloyd Dupont

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);
}
 
L

Lloyd Dupont

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);
}
 
M

Michal Talaga

(*): 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.
 
A

Alvin Bruney [MVP - ASP.NET]

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

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

Lloyd Dupont

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/TextComponentDemo.jnlp
http://java.sun.com/docs/books/tutorialJWS/uiswing/components/example-1dot4/TextSamplerDemo.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....
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top