Memory leak and performance issue with WPF's TreeView - wpf

I'm running into a problem with the WPF TreeView control.
I think I ran into a memory leak issue with this control and also some performance issues.
I've prepared a simple demo solution where you can see these problems.
Download link: http://www.custom-projects.com/TreeViewMemoryAndPerformanceIssue.zip
I'm creating the tree based on some domain objects. The objects are wrapped in view models.
The number of levels is not restricted, but currently we have a maximum of 3 levels.
So, each view model can have children.
When you click on the up/down buttons of the UpDown control and don't release the mouse button you will see, that the update speed of the int value will get slower and slower and the memory consumption constantly rises.
What I'm doing: When you click on the up/down button the value is sent to the view model via data binding. In the setter I'm raising a event. Our application consists of different view models and if someone is changing data in one of them, the others are notified through these DataChanged events.
For simplicity, my demo solutions just consists of the NavigationViewModel. So it listens
for the DataChanged event and if fired, the tree is rendered.
Because we don't have a list which will always be the same (and just rows are added or removed), I'm not using a ObservableCollection. We always have to regenerate the list based on the objects the user has added/created.
Anyways, I'm adding these view models to a list and raise the NotifyPropertyChanged event
so that WPF updates the tree. Works well but the more the list is updated, the slower the application gets (and memory goes up).
I checked, that the item view models are garbage collected and they are, so I don't see
something wrong on my side. I also did some performance profiling. It looks, that the
issue is on the WPF side, because my code does not slow down. The Application.Run method
execution time rises... Strange thing.
Does anyone has an idea, why the memory is going up and never gets released and why the
performance starts to decrease the more often the TreeView updates itself?
I would appreciate any help or comment on this issue.
Thanks,
Christian

I profiled your test application using ANTS Memory Profiler and you can see that your classes 'NavigationItemBaseViewModel' and the array "NavigationItemBaseViewModel[]" are still held in memory by references, and this is getting worse with each increment.
If you slowly increment and allow the update to happen, then the references are broken and objects disposed. All good.
However, if you increment fast/continuously then you see that your references are not broken, thus the arrays are kept in memory.
The increments get slower each time because your application is having to update a lot of these view models, at increment #58 I had 172 arrays holding between them 517 NavigationItemBaseViewModel's.
Where with "normal" functionality you only have 4 arrays and 13 NavigationItemBaseViewModel's.
Hope that helps, I would recommend you profile your memory if you cannot figure out your logic where new are creating new arrays. Typically it is best to reuse arrays.
Profiler I used is here: http://www.red-gate.com/products/dotnet-development/ants-memory-profiler/index2
Hope that helps.

I was investigating lots of memory leaks in WPF and i find this tool very useful: http://www.jetbrains.com/profiler/ It has trial period of 10 days (i've just checked) so i hope you will be able to find your problem.

Related

WPF View leak - invisible, but still rendered in the background

There is a complex App, I try to simplify the scenario. There is a host .exe (.NET), which contains lots of controls (ActiveX, .NET, WPF).
One control is basically a grid with items (call it "list"), and when new selection happens, it sends a message to another WPF control (call it "DataView"). "DataView" will display details of the current selection of "list". When DataView receives that message, it will re-create it's ViewModel, and assign to its DataContext, so re-create its View.
Its View is very complex (XAML declared), full of controls, templates, and also contains several Images (type: NonDPIImage, derived from Image, with a few basic non-important change, just consider it as Image), and it's Source is a Converter, which creates the BitmapImages.
<Image.Source>
<MultiBinding Converter="{StaticResource ImageConverter}">
...
It works fine, but I noticed that after selection changes the "DataView" update is getting slower and slower.
I debugged, and found that after several selection changes, all previous Views are still in the memory, and all are rendering its content, so the ImageConverter is called for all previous Views, thus it's getting slower and slower.
I tried to profile, this is what I see after 10+ selection.
You see the previous Views are still in the memory (lower prio problem), with the Images, and those are still being rendered (high prio problem), making the App slower and slower.
I am not really familiar with WPF, I read after leaks (mostly not DependencyProperty is used or similar), but this control is so difficult that first I wand to quickly workaround, so prevent rendering the leaked Views, and later on investigate the memory issue. (of course both would be the best...)
I tried that before DataContext assigned to new value, set the current View Image.Source to null, so at least the leaked Image will not render itself, but that caused the new View(!) also to lose its Image.Source, looks like WPF is caching or sharing like some static data?
As my first prio is to stop the "invisible render", after this I tried to set some of the model properties to null before creating the new one (so it would still leak, but at least no render anymore), so when Converter will receive properties to create the image, will see it's null, and skip the render.
But it behaves very strange!
For the leaked instances the breakpoint is not hit in the properties_get code, like as WPF cached the values or so?
This prevented me this path to continue.
Any help / idea would be appreciated guys.
Can you post your ImageConverter code?
the thing is creating an image from code and serving it as source for Image object,
can create strong link between them and memory leaks in scenarios like yours.
Try looking here:
https://stackoverflow.com/a/21878235/7722174
I think I found the issue: there was a message hook added to the View HwndSource (AddHook()) , but was not removed. This kept the whole View (see the red rectangled class) alive.
Now if I call MyHwndSource.RemoveHook(WndProc) in the UserControl_Unloaded, the View will be also GCd.

How to let ViewModel trigger View update

I need real time charting (100-200ms updates) of a maximum of 20 series. After some research I settled on syncfusion because I can use the community license and at first sight it seems performant. The only drawback seems to be the sometimes lacky MVVM support.
To get a good realtime performance I found this blog post:
https://www.syncfusion.com/blogs/post/Deliver-high-performance-charts-with-Syncfusions-WPF-chart-control.aspx
I'm especially interested in the 'batch update' section because all 20 series will get updated at the same time, there's no need to rerender the chart 20 times.
An alternative seems to be this: http://help.syncfusion.com/wpf/sfchart/how-to/add-range-of-points-dynamically
I have yet to investigate the differences.
But how can I make this MVVM friendly.
Thanks for your advice!
This requirement can be achieved by accessing the SfChart control from its view(UserControl) which was initialized in the ViewModel class, to have access on SuspendNotification and ResumeNotification methods in SfChart.
Real time updates can be achieved in two ways.
By using auto-scrolling feature, to maintain a fixed amount point in view while real time update and also there is a provision to view old data through scrolling.
By removing the first record from the collection while adding new record at the end.
Demo Samples : Real_Update_Samples

WPF performance problem with CommandManager

We've created a new, quite complex, WPF application from the ground up and have run into a performance problem as the number of commands registered with the CommandManager increase. We're using simple lightweight commands in our MVVM implementation, however the third party controls we're using (Infragistics) do not, and call CommandManager.RegisterClassCommandBinding liberally to add RoutedCommands. The performance problem manifests itself as a perceived sluggishness in the UI when responding to user input, for example tabbing between controls is slow, text input is 'jerky' and popup animation is 'clunky'. When the app is first fired up the UI is snappy. As more screens containing Infragistics grids are opened the performance deteriorates.
Internally, the CommandManager has a private field named _requerySuggestedHandlers, which is a List< WeakReference>. I've used reflection to get a reference to this collection, and I've noticed that when I call .Clear(), the responsiveness of the UI improves back to its initial state. Obviously I don't want to go round clearing collections that I know little about, especially using reflection (!) but I did it to see if it would cure the performance problems, and voila it did.
Normally, this situation would clean itself up after a certain amount of time passes. However, the collection of WeakReferences (_requerySuggestedHandlers) will only get trimmed once a garbage collection is initiated, which is non-deterministic. Because of this, when we close down windows containing grids (Infragistics XamDataGrid), the CanExecute property for 'dead' grid commands continue to be evaluated unnecessarily, long after the window is closed. This also means that if we close down a number of windows, the performance is still sluggish until a garbage collect is initiated. I understand that this can happen on allocation, and I've seen that myself because if I open a further window this causes the initial memory (from the disposed Windows) to be collected and performance returns to normal.
So, given the above, here are my questions:
How, and from where, does CommandManager.InvalidateRequerySuggested() get called? I haven't found any documentation on MSDN that explains this in any great detail. I hooked up to the CommandManager.RequerySuggested event and it looks like it's being called whenever controls lose focus.
Is is possible to suppress CommandManager.InvalidateRequerySuggested() being called in response to user input?
Has anyone else run into this issue, and if so, how have you avoided it?
Thanks!
This sounds like one of the rare cases where deterministically calling GC.Collect() is the right thing to do. The ordinary argument against it is that the garbage collector is smarter than you are. But when you're dealing with WeakReference objects, you enter territory where you may know something that the garbage collector doesn't. Kicking off garbage collection is certainly better than clearing _requerySuggestedHandlers - among other things, it won't do anything to the WeakReference objects that point to controls that are still alive.
I'd choose this over trying to figure out how to suppress RequerySuggested, since that would screw up the behavior of those commands that you still care about.

TreeView.Items.Filter Memory Leak, HELP!

I'm having this terrible problem, i have a tree view and i'm using the it's Items.Filter to support search options.
My TreeView is also virtualized cuase it contains tones of items and if not virtualized it takes a minute for the UI to load.
My problem is that whenever i set a filter it seems that the memory usage grows by 20M!!!
I don't understand why the ListBox won't use the items it already has and why it needs to create new items (i see calls to the child item's constructors)
Why the hell won't it release the old UI elements from the memory?!
PLEASE HELP!!!
Gili
Are you sure that the old UI elements aren't released?
Try calling GC.Collect(); and see if you loose those 20M, this is not considered a good thing to do but it would verify if the UI elements are released or not.
And does it grow 20M each time you set a filter or just the first time?

Is it possible to refresh a CollectionViewSource too often? Having some strange issues occur

I've got these ListViews bound to a couple of CollectionViewSources. Those are in turn bound to ObservableCollection lists which have plenty of data that updates quite often (it monitors a 32 player game server and displays player metadata and events). I wouldn't ever call Refresh() on the view if it weren't for the apparent necessity to make sure it is continually sorted by Score and to ensure added/removed players are updated on the UI.
Now the issue I've run into is that too many refreshes to the Views will cause them to lose the ability to open a context menu. You can right-click all you want but it will not appear until you destroy the form and re-instantiate it (an unacceptable workaround).
Has anybody ever seen this behavior, and know how to get around it? Initially I was Refreshing as often as it felt it needed to -- this caused the issue almost immediately. I reduced these Refreshes to every 5 seconds and now it happens but not quite as often.
We have had several problems with the CollectionViewSource. It causes lots of performance issues after openening the same window for appr. 5 times. It might be because we were using an LLBLGen collection as items source, but I will never use the CollectionViewSource again.
Now, I wouldn't refresh the view manually. Your ObservableCollection is responsible for updating the data. Try removing the CollectionViewSource for now (so you will lose the sorting ability), and see if the problem still occurs. If it disappears, you will need another way to sort your collection.

Resources