I am using several Blend behaviors and triggers on a silverlight control. I am wondering if there is any mechanism for automatically detaching or ensuring that OnDetaching() is called for a behavior or trigger when the control is no longer being used (i.e. removed from the visual tree).
My problem is that there is a managed memory leak with the control because of one of the behaviors. The behavior subscribes to an event on some long-lived object in the OnAttached() override and should be unsubscribing from that event in the OnDetaching() override so that it can become a candidate for garbage collection. However, OnDetaching() never seems to be getting called when I remove the control from the visual tree... the only way I can get it to happen is by explicitly detaching the problematic behaviors BEFORE removing the control and then it is properly garbage collected.
Right now my only solution was to create a public method in the code-behind for the control that can go through and detach any known behaviors that would cause garbage collection problems. It would be up to the client code to know to call this before removing the control from the panel. I don't really like this approach, so I am looking for some automatic way of doing this that I am overlooking or a better suggestion.
public void DetachBehaviors()
{
foreach (var behavior in Interaction.GetBehaviors(this.LayoutRoot))
{
behavior.Detach();
}
//continue detaching all known problematic behaviors on the control....
}
What you really need in this case is not some way to automatically detach but to ensure that the reference held by the long lived object does not keep the behaviour (and therefore everything else it has a reference to) from being garbage collected.
This is acheived by implementing a Mediator pattern. The concept is that you don't give the long-lived object a delegate with a reference to your Behaviour, instead you create a Mediator class as a go-between. The mediator attaches to the long-lived objects event and holds a WeakReference to the behaviour. When the long-lived object fires the event the mediator checks that the WeakReference is still alive, if so calls a method on it to pass on the event. If when the event occurs the mediator finds that the WeakReference is no longer alive it detaches its event handler from the long lived object.
Hence there is nothing stopping the behaviour and everything else involved from being garbage collected all thats left is a very small mediator instance with a dead reference still attached to the long-lived object. Since these mediators are tiny they don't represent a real problem and even those will disappear the next time the event fires.
Fortunately you don't have to build this stuff yourself others have already done it. It is called the WeakEventListener. This blog: Highlighting a "weak" contribution; Enhancements make preventing memory leaks with WeakEventListener even easier! has an excellent set of links on the subject.
Joost van Schaik offers an alternative way to clean up references from attached behaviors, while avoiding the problem with the memory leak. It depends on doing the cleanup work using delegates of the Loaded and Unloaded events of the AssociatedObject.
He also offers a code-snippet for generating stubs for attached behaviors.
Related
This question already has answers here:
How to update only a property in an observable collection from thread other than dispatcher thread in WPF MVVM?
(3 answers)
Closed 1 year ago.
The suggested duplicate thread did not address my question
So it is my understanding that a WPF application handles everything UI related, button presses, updates to observable collections through the dispatcher thread, which can be called with Application.Current.Dispatcher.Invoke(Update UI element here), while changes to models and data can be handled by background threads normally.
What I don't understand is why you need to call the dispatcher for say updating an observable collection Bound to a Combobox, but yet when I want to update the progress bar or text in a textbox or if a button is enabled I don't need to call the dispatcher. Everything I read states that the dispatcher is used for handling and updating the UI. Are textboxes, the status of progress bars, and whether or not a button is enabled not see as UI?
What is the difference between an Observable collection and text/progress bars that makes calling the dispatcher not required?
Almost any call to a WPF UI element should happen on the main thread of the application.
This is usually done through the methods of the Dispatcher associated with this thread.
The dispatcher can be obtained from any UI element, but usually it is obtained from the application: Applicatiion.Current.Dispatcher.
If you do not assign values directly to the properties of UI elements, but use bindings for this, then the bindings mechanism has built-in marshaling of value assignment into the flow of the UI element.
Therefore, the INotifyPropertyChanged.PropertyChanged event can be raised on any thread.
When the observable collection changes, the INotifyCollectionChanged.CollectionChanged event is raised.
It is not provided for automatic marshaling to the UI thread.
But the collection can be synchronized with the BindingOperations.EnableCollection (...) method.
Then it can be changed (using synchronization) in any thread.
If such synchronization has not been performed, then it can be changed only in the UI thread.
In addition to these events, there is also ICommand.CanExecuteChanged.
There are no additional marshaling or synchronization methods provided for it.
Therefore, it can be raised only in the UI thread.
This is usually built into the WPF implementation of ICommand and the programmer doesn't need to worry about it.
But in simple (mostly educational) implementations, there is no such marshaling.
Therefore, when using them, the programmer himself must take care of the transition to the UI thread to raise this event.
So basically in MVVM practice you no matter what you would have to use a dispatcher to use BindingOperations.EnableCollectionSynchronization(fooCollection, _mylock)); correct?
Yes.
For the application of the collection, you understood correctly.
Here only the problem of separation of the View and ViewModel functionality arises.
You can only call "EnableCollectionSynchronization" on the View or on the main UI thread.
But you are implementing the collection in the ViewModel.
Also, in order not to clog up memory, when deleting a collection (replacing it with another, clearing the bindings that use it, replacing the ViewModel instance, etc.), you need to delete the created synchronization using the "DisableCollectionSynchronization (collection)" method.
In this regard, if a single instance of the ViewModel is used throughout the application session, then using "EnableCollectionSynchronization ()" is the simplest solution.
Example:
public class MainViewModel
{
public ObservableCollection<int> Numbers { get; }
= new ObservableCollection<int>();
protected static readonly Dispatcher Dispatcher = Application.Current.Dispatcher;
public MainViewModel()
{
if (Dispatcher.CheckAccess())
{
BindingOperations.EnableCollectionSynchronization(Numbers, ((ICollection)Numbers).SyncRoot);
}
else
{
Dispatcher.Invoke(()=>BindingOperations.EnableCollectionSynchronization(Numbers, ((ICollection)Numbers).SyncRoot));
}
}
}
But if many VM instances are used, with mutual nesting and dynamic addition and removal (for example, this can be the case when implementing a tree and viewing it in a TreeView), then using "EnableCollectionSynchronization ()" becomes not trivial.
If you do as I showed in the example above, then due to the fact that the reference to the synchronization object, to the collection, will be saved, they will not be deleted from memory and, accordingly, unnecessary instances of ViewModel will not be deleted.
And this will lead to a memory leak.
Therefore, in practice, marshaling of collection changes to the UI thread is often used.
It is also possible to embed in the INotifyCollectionChanged implementation, as well as marshaling to the UI thread, and calling "EnableCollectionSynchronization () / DisableCollectionSynchronization ()" while subscribing / unsubscribing to the CollectionChanged event.
The implementation of the ObservableCollection does not have this, but there are custom implementations of the observable collections in various packages where the similar is implemented.
And their use frees the programmer from creating routine, specific, repetitive code.
Unfortunately, I cannot tell you exactly what the package contains the required implementation.
I prefer to use my own implementations.
I'm working on new WPF application. And I'm just wondering do I have to dispose or clear memory in any way in Views or View Models?
I only found information, that I should do it when using com ports or any external devices.
This is a very general question, so it is hard to provide a specific answer. .NET applications are garbage collected, so in general things are cleaned up once you no longer reference them anywhere.
Objects that Need Cleanup
There are certain things that the garbage collector will not clean up for one reason or another. In the vast majority of these cases, the class you are working with will implement the IDisposable interface. The most common things that I run into that are disposable are streams and stream-related classes. However, it is a good idea to check anytime you are using something you are unsure about.
So when it comes to views and view models in WPF, the same rules apply. If you are using something that implements IDisposable, then you need to either call Dispose on it when you are done, or wrap the creation of the object in a using block if it makes sense for the use case.
In some cases, a viewmodel might own an instance of a disposable object. In such a case, the viewmodel should itself implement IDisposable, and ensure it disposes the object within its own Dispose method. You will then need to call Dispose on the viewmodel when you are done with it.
Events
A common source of memory leaks in .NET applications are event handlers. Once an application starts to have some complexity to it, you might find that a temporary object (like some viewmodels) will want to register for events with things that have a longer lifespan (such as a service or persistent utility). Registering an event handler using the += operator creates a hidden reference from the event sending object to the event handling object. You will need to remove these handlers using the -= operator to allow the garbage collector to cleanup the handler and the object that owns it.
If you find yourself in a situation where you do not have a valid place to ensure an event is unregistered, consider using a WeakEventManager to add the handler instead of the += operator. This allows an object to handle events without the event sender having an explicit reference to the handling object. However, there is a very small amount of additional performance and memory overhead registering for events this way, so I would not recommend blindly switching all of your event handlers to weak events. Use it just where you need to.
Keep in mind that there are plenty of cases where not unregistering an event is ok and will not cause any memory leak. This is usually true when both the event sender and the event handler have the same life cycle, as is usually the case with a view and its associated view model. In such a case, it is fine for the view to register for events on the viewmodel and never unregister. As long as both the view and viewmodel stop being referenced by anything, they will get cleaned up regardless of the event that links them together.
Summary
There are no hard rules on whether views and viewmodels need any special handling to clean them up. If they are making use of a feature that requires special cleanup, then you will have to deal with that in whatever way is appropriate.
If you are not using any disposable objects, or other things that need explicit cleanup, then all you have to worry about is removing references to your views and viewmodels when you no longer need them.
If you want more technical information about the garbage collector, take a look at this article. Having an understanding of how it works may help you better understand when and how to clean things up.
I understand the Weak Reference and the Weak Event Pattern.
One place where the weak event pattern is used is in DataBinding between Controls and DataModel.
During the process of DataBinding, if the DataModel support INotifyPropertyChange, the Control will ask the DataModel to advise him on change through the event.
Without weak event the DataModel would have kept a hard ref on the control. Due to that reference, the control could not be marked as available for GC at the same time as the window become available to be GC.
Microsoft decided to use weak reference to solve this issue.
I wonder if other alternatives like the proposed one would not have been better ?
Alternative: Implement IDisposable on Window with code that pass its children UiElements in order to ask them to remove their DataBinding to the DataModel ?
What would have been wrong with that solution ?
There's one fundamental advantage in using weak events: the task to unbind the Control from the DataModel is left to the garbage collector itself. The garbage collector typically runs in a low-priority thread that is only activated when the system is idle or when there's need to free up memory, so it doesn't slow down other activities. By contrast, having IDisposable detach the Control from the DataModels means that if you manually dispose of the Control, the unbinding has to take place in the regular caller's thread.
Another aspect (and this is mandated by the MVC pattern) is to leave the model independent from the view. If you think of object lifetime as a dependency, weak references are exactly what it takes to keep the models independent, since you don't have to rely on the controls' cooperation to release the bindings.
I have read a lot about this topic, and still I don't have the clear path how to proceed. Can anyone point to some resource (or explain) that shows in detailed step how to find the reason why some objects dctor is not called.
basically my logic for testing leak is this (WPF application):
create some View/ViewModel
close the View
call GC.Collect()
After a few seconds a dctor on ViewModel class is normally called, but on my application is never called. I would like to know which object is holding a reference to it at that time, since in my opinion it is the way to find the cause of memory leak.
This classes do not user any unmanaged resources, and do not have IDisposable implemented, which means there is no SupressFinalize call to prevent desctructor execution.
Edit: ViewModel is retrieved through a Static property on ViewModelLocator, and is added List. This is required by TabControl, which needs collection of view models to bind to. View and ViewModel are connected through DataTemplate.
First, search for non-unsubscribed event handlers and static references pointing to your ViewModel, even indirectly. Since you're in a WPF application, also ensure that you don't use DependencyPropertyDescriptor.AddValueChanged which is known to cause leaks by using static references.
If you can't find anything manually, use the awesome (this is my opinion, I'm in no way affiliated with them) SciTech .NET Memory Profiler. You can see for every object all the references it holds and which other objects are holding a reference to it, in a nice graph
view. It also warns you for common memory problems.
EDIT:
ViewModel is retrieved through a Static property on ViewModelLocator
Search no longer, you have your leak. Static references prevent objects from being garbage collected. Remove the static reference or wrap it in a WeakReference.
I have a TabControl in WPF / MVVM that is bound to an ItemsSource on top of an ObservableCollection. Each tab has its own collections and bindings with components such as Images, Richtextboxes, and user input boxes, and everything seems to work well.
However, I have noticed that each time I switch a tab, it uses about 100k of system memory which never gets reclaimed! If I hold ctrl-tab down to cycle through all tabs, I can use up 200 megs of memory within a minute.
Now - I created a blank WPF app with just a tab control, and it also uses memory for each tab switch (albiet MUCH less). Is this just some .NET bug, or a feature? Maybe it stores a breadcrumb trail, maybe its used for debugging (although I compiled in release mode).
How do I reclaim my memory? Or better yet, not lose memory to tab switchings?
This fixed the issue to me:
http://blingcode.blogspot.com/2010/10/memory-leak-with-wpfs-richtextbox.html
Basically add two attributes to each RichTextBox :) :)
IsUndoEnabled="False" UndoLimit="0"
You might want to check if there are any event handlers left behind.
In the case where you registered an event in other control, the garbage collector will not collect the objects that are no longer needed, because the event is still attached so to speak.
So if you registered Loaded somewhere in code behind
public ParentEditor()
{
InitializeComponents();
control.Loaded += OnControlLoaded;
}
or in XAML or the ParentControl
<Control Loaded="OnControlLoaded" />
You basically have two solutions to tackle this problem:
Solution 1 - Remove event handlers when they are no longer needed:
You might want to remove this handler in the unloaded of the parent control like so:
public ParentEditor()
{
InitializeComponents();
control.Loaded += OnControlLoaded;
this.Unloaded += OnParentUnloaded;
}
void OnParentUnloaded(object sender, RoutedEventArgs e)
{
//Remove unloaded event
this.Unloaded -= OnParentUnloaded;
//Remove event from child control
control.Loaded -= OnControlLoaded;
}
You can also use the Unloaded event of the child control of course.. that is up to you..
Solution 2 - Using the WeakEvent pattern:
Another solution for events would be the WeakEvent pattern, which bypasses this problem.
Why Implement the WeakEvent Pattern?
Listening for events can lead to
memory leaks. The typical technique
for listening to an event is to use
the language-specific syntax that
attaches a handler to an event on a
source. For instance, in C#, that
syntax is: source.SomeEvent += new
SomeEventHandler(MyEventHandler).
This technique creates a strong
reference from the event source to the
event listener. Ordinarily, attaching
an event handler for a listener causes
the listener to have an object
lifetime that influenced by the object
lifetime for the source (unless the
event handler is explicitly removed).
But in certain circumstances you might
want the object lifetime of the
listener to be controlled only by
other factors, such as whether it
currently belongs to the visual tree
of the application, and not by the
lifetime of the source. Whenever the
source object lifetime extends beyond
the object lifetime of the listener,
the normal event pattern leads to a
memory leak: the listener is kept
alive longer than intended.
In either case, good luck.. its quite hard to find leaks like the one you are experiencing!
Good advice, but in the end I decided a bindable textblock was more useful and simpler than a richtextbox. I never found out what was causing the leak - but it was definitely in the bindablerichtextbox code (OnInitialized was being called each time a tab switched, which was beyond my control).
The leaks are gone, and my app runs quicker because of the use of the simpler bindable textblock.