Memory Leak - An ItemsControl within another ItemsControl?
Seeing some interesting memory leak and would like to share here and see if anyone could help out with some insights.
I have recently implemented a VirtualizingWrapPanel in C++, I use it to initialize and recycle a bunch of card-like UIElements in an ItemsControl bind through XAML. In each card's DataContext, it has another ItemsControl containing a bunch of Noesis::Path to render some graph (stored in ObservableCollection in the DataContext).
Apparently the allocation of these Noesis::Path are generating leaks. At first I thought it was a bug in the V-WrapPanel, but the memory leaks still occur when switching to a VirtualizingStackPanel.
When the VirtualizingWrapPanel virtualizes (recycles) the card container, its ItemContainerGenerator properly recycles the object (it calls the Remove function with the boolean recycleContainers set to true), however, I notice the same Remove function in the ItemContainerGenerator for the Noesis::Paths never gets called. I suspect that is where the leak is from? Wondering if anyone here could help shed some light.
I have recently implemented a VirtualizingWrapPanel in C++, I use it to initialize and recycle a bunch of card-like UIElements in an ItemsControl bind through XAML. In each card's DataContext, it has another ItemsControl containing a bunch of Noesis::Path to render some graph (stored in ObservableCollection in the DataContext).
Apparently the allocation of these Noesis::Path are generating leaks. At first I thought it was a bug in the V-WrapPanel, but the memory leaks still occur when switching to a VirtualizingStackPanel.
When the VirtualizingWrapPanel virtualizes (recycles) the card container, its ItemContainerGenerator properly recycles the object (it calls the Remove function with the boolean recycleContainers set to true), however, I notice the same Remove function in the ItemContainerGenerator for the Noesis::Paths never gets called. I suspect that is where the leak is from? Wondering if anyone here could help shed some light.
-
-
sfernandez
Site Admin
- Posts: 3364
- Joined:
Re: Memory Leak - An ItemsControl within another ItemsControl?
Just to simplify the scenario and help detecting the origin of this leak:
-If you remove the inner ItemsControl from your card-like control, do you get any memory leak?
-If not, if you have a single card-like (without being inside an ItemsControl) with the inner ItemsControl containing the paths, do you get any memory leak?
-If you remove the inner ItemsControl from your card-like control, do you get any memory leak?
-If not, if you have a single card-like (without being inside an ItemsControl) with the inner ItemsControl containing the paths, do you get any memory leak?
Re: Memory Leak - An ItemsControl within another ItemsControl?
hey thank you for the reply @sfernandez
when I removed code block between <ItemsControl.ItemTemplate> and </ItemsControl.ItemTemplate> to prevent the initialization of Noesis::Path items, the memory leak went away.
One thing I didn't mention in my original post, is that we are using the C++ implementation of Noesis.
Yes I have experimented with that. In the following XMAL for the card component:Just to simplify the scenario and help detecting the origin of this leak:
-If you remove the inner ItemsControl from your card-like control, do you get any memory leak?
Code: Select all
<!-- other parts of components -->
<Border
Background="{StaticResource ColorGrey2}"
CornerRadius="4">
<Grid Margin="4,32,4,0">
<Viewbox Stretch="Fill">
<ItemsControl ItemsSource="{Binding PathItems}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid IsItemHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Path
Data="{Binding Geometry}"
Fill="{Binding Fill}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Viewbox>
</Grid>
</Border>
<!-- other parts of components -->
One thing I didn't mention in my original post, is that we are using the C++ implementation of Noesis.
-
-
sfernandez
Site Admin
- Posts: 3364
- Joined:
Re: Memory Leak - An ItemsControl within another ItemsControl?
I see the card component contains an ItemsControl, but it is using a Grid to show the items. This means no virtualization is applied there, and all the items in the "PathItems" collection will be instantiated when the card component is created.
And as you are recycling the card components in the outer ItemsControl, the container is not destroyed, it gets reused and connected to a new card when it is shown in the outer ItemsControl. At that moment is when the bindings will be updated and the inner ItemsControl will destroy the old paths and create the new ones.
Are you getting memory leak warnings when closing the application? Or why do you think there is a memory leak in this scenario?
And as you are recycling the card components in the outer ItemsControl, the container is not destroyed, it gets reused and connected to a new card when it is shown in the outer ItemsControl. At that moment is when the bindings will be updated and the inner ItemsControl will destroy the old paths and create the new ones.
Are you getting memory leak warnings when closing the application? Or why do you think there is a memory leak in this scenario?
Re: Memory Leak - An ItemsControl within another ItemsControl?
hi @sfernandez
Noesis::Path appears to be both Item and Container. When ItemContainerGenerator calls GenerateNext, I see the Path object's reference count increases by 2, which makes sense since both item and container are the same Noesis::Path. However, when new ItemsControls binds to the recycled container (this container is from the content card in the outer ItemsControl) and ItemContainerGenerator::RemoveAll is called, I see only one ref count decrementing. Is that normal? I don't see a case in neither ItemContainerGenerator nor ItemsControl::ClearContainerForItemOverride handling the case where container == item. Could this be the potential cause of this memory leak?
This is a speculation based on once removing the ItemsControl containing the Noesis::Path, memory leak no longer observed in the Inspector. Also when I turn on the memory tracker, it does report Noesis::Path as part of the leak. Including part of the callstack from one of the detected leaksAre you getting memory leak warnings when closing the application? Or why do you think there is a memory leak in this scenario?
Code: Select all
Number of allocations:120
Total size allocated 37440 (36KB) Last sequence number 666391
Noesis::Alloc (code\thirdparty\noesisgui-source\noesis\src\packages\core\kernel\src\memory.cpp:97)
Noesis::BaseObject::operator new (code\thirdparty\noesisgui-source\noesis\src\packages\core\kernel\src\baseobject.cpp:30)
Noesis::GeometryGroup::GeometryGroup (code\thirdparty\noesisgui-source\noesis\src\packages\gui\core\src\geometrygroup.cpp:23)
Noesis::Path::Path (code\thirdparty\noesisgui-source\noesis\src\packages\gui\core\src\path.gui.cpp:28)
<lambda_8495fa16132bb210ab6d25ede3a9e50a>::operator() (code\thirdparty\noesisgui-source\noesis\src\packages\gui\core\src\gui.core.cpp:411)
<lambda_8495fa16132bb210ab6d25ede3a9e50a>::<lambda_invoker_cdecl> (code\thirdparty\noesisgui-source\noesis\src\packages\gui\core\src\gui.core.cpp:411)
Noesis::Factory::CreateComponent (code\thirdparty\noesisgui-source\noesis\src\packages\core\kernel\src\factory.cpp:64)
Noesis::FrameworkElement::Clone (dcode\thirdparty\noesisgui-source\noesis\src\packages\gui\core\src\frameworkelement.cpp:833)
//...and more belowNoesis::Path appears to be both Item and Container. When ItemContainerGenerator calls GenerateNext, I see the Path object's reference count increases by 2, which makes sense since both item and container are the same Noesis::Path. However, when new ItemsControls binds to the recycled container (this container is from the content card in the outer ItemsControl) and ItemContainerGenerator::RemoveAll is called, I see only one ref count decrementing. Is that normal? I don't see a case in neither ItemContainerGenerator nor ItemsControl::ClearContainerForItemOverride handling the case where container == item. Could this be the potential cause of this memory leak?
-
-
sfernandez
Site Admin
- Posts: 3364
- Joined:
Re: Memory Leak - An ItemsControl within another ItemsControl?
Does the 'PathItems' collection contains Path elements? From the previous xaml you attached didn't seem like that (I saw a binding to a Geometry property that is not defined in the Path class).Noesis::Path appears to be both Item and Container. When ItemContainerGenerator calls GenerateNext, I see the Path object's reference count increases by 2, which makes sense since both item and container are the same Noesis::Path.
I'll do some tests with that scenario in mind and let you know what I find.
-
-
sfernandez
Site Admin
- Posts: 3364
- Joined:
Re: Memory Leak - An ItemsControl within another ItemsControl?
Even with a collection of Path elements the behavior is as expected, when RemoveAll is called the references stored by the ItemContainerGenerator are correctly released, and after that the ItemsChanged event is called and the items host panel releases its own reference to the Path elements. Each Path has only a remaining reference corresponding to the viewmodel collection, so everything looks fine to me.
Re: Memory Leak - An ItemsControl within another ItemsControl?
Thank you for checking on your side @sfernandez! I did similar test last night as well and the result are aligned with what you just shared (basically recording the ref count when an object upon enter versus exit, it was correctly set to 1).
I will review other part of our code. Will update here when I spot something.
I will review other part of our code. Will update here when I spot something.
-
-
sfernandez
Site Admin
- Posts: 3364
- Joined:
Re: Memory Leak - An ItemsControl within another ItemsControl?
Ok, please let me know if you find anything and we would try to reproduce it.
Who is online
Users browsing this forum: Bing [Bot], Google [Bot] and 3 guests