Stopping Observation

Dec 7, 2009 at 8:30 AM
Edited Dec 7, 2009 at 9:10 AM

Let's say I do this...

IValueProvider<int> vp = ExpressionObserver.Execute(() => X.SomeInteger);
vp.PropertyChanged += SomeHandler;
... Do stuff requiring observation ...
vp.PropertyChanged -= SomeHandler; vp = null;

Will the transformation chain get garbage collected, or will X.PropertyChanged still be pointing to it and prevent that from happening?  I have long lived source objects in my application and I'm wondering if there's any way to get Obtics to truly disconnect itself from the source objects when I'm done observing.

I'm concerned about the possibility for memory leaks here.

Coordinator
Dec 7, 2009 at 4:07 PM

Yes, it should get cleaned up. Unless it is used somewhere else.

Also; the value providers tend to have a longer lifetime and can easily end up in the 3rd level heap. This means it may take some time before detached value providers get garbage collected. In the meantime they can always be reused.

It is important to always detach any manualy added event handlers.

Dec 7, 2009 at 6:19 PM

Thanks for the help once again!  Your time is much appreciated.  We are enjoying Obtics more all the time.

I'm wondering, how do you "disconnect" yourself from X in the above example?  You mentioned that it's important to remove the event handler... is there some sort of cascade effect when the top level handlers are all disconnected?  I'm just curious because this was one of the major problems we had from an implementation perspective in our own system.

Dec 8, 2009 at 7:09 PM

Along the same lines, if I have an object O that is observing object X, and I drop all references to O, will the transformation chain get garbage collected?

If not, should I be adding a Dispose() to O that disconnects from the event handler manually?

Appreciate your advice on this tricky subject.

Coordinator
Dec 9, 2009 at 10:14 AM

The transformation pipelines keep track of the number of registered event listeners. As soon as this number drops to 0 they themselves will unregister from any events they depend on. So yes; it is a cascade.

You can get the same sort of memory leak as you would get with ordinary events. An event registration chain from X to O will keep O allive. If you have any manual event registrations in O you should always get rid of them before you let go of O. This will probably mean implementing IDispose on your object. You could also keep track of your own event listeners and unregister when all your clients have unregistered. A combination is also possible.

It would be easier, though less classic, to 'just' return IValueProvider<T> s from your properties.

Dec 9, 2009 at 3:44 PM

I've also played with the possibility of using weak references to solve the problem.  The idea I was testing was to disconnect from the source PropertyChanged handler if the target of the event is null.  This enables automatic garbage collection but has the drawback of not disconnecting a handler unless a PropertyChanged event is actually thrown.

It sounds like you've probably looked into this... does WPF disconnect its handlers when its windows go away?

Coordinator
Dec 9, 2009 at 9:14 PM

Obtics doesn't use weak events especially because WPF does. I often have properties that return IValueProviders that are created (or retrieved from the carrousel) on the fly (not stored in a local field or anything). WPF can bind directly to the Value of the returned IValueProvider. As long as WPF has an event registration the non-weak events (from the source up) will ensure that the transformation pipeline will remain allive. If Obtics would use weak events the pipeline would be garbage collected and no more updates would get through to the WPF binding.

When WPF is done it unregisters. The transformation pipeline in turn will unregister from its source and can be garbage collected thus immediately reducing memory stress.

There is an issue though with WPF bindings to objects that themselves have a strong reference path to the target of the binding. The binding uses the PropertyDescriptor.AddValueChanged method to register for property change notifications. This in turn will store a strong reference to the property owning object in a static container! And that means that because of the strong reference path from the object to the binding target that target will never be garbage collected and the binding never cleared -> memory leak.

So; if you have a WPF element that is not meant to stay arround for ever. Don't bind it to an observable expression that has that same element or a parent of that element as one of it's dependencies. I usually create a backing store (ValueProvider.Dynamic()) for a value my observable expression depends on and then bind WPF to that backing store. WPF can then safely bind to my observable expression without the risk of creating the mentioned problem. So I don't use TextBox.Text directly in my observable expression but create a field IValueProvider<string> t = ValueProvider.Dynamic<string>(); I bind TextBox.Text to that field and base my observable expression on it. Thus preventing a strong reference path from my observable expression to the TextBox.