lukeyen
Topic Author
Posts: 7
Joined: 22 Dec 2021, 06:00

Memory Leak - An ItemsControl within another ItemsControl?

01 Jul 2022, 06:26

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.
 
User avatar
sfernandez
Site Admin
Posts: 3364
Joined: 22 Dec 2011, 19:20

Re: Memory Leak - An ItemsControl within another ItemsControl?

01 Jul 2022, 10:37

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?
 
lukeyen
Topic Author
Posts: 7
Joined: 22 Dec 2021, 06:00

Re: Memory Leak - An ItemsControl within another ItemsControl?

05 Jul 2022, 18:51

hey thank you for the reply @sfernandez
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?
Yes I have experimented with that. In the following XMAL for the card component:

<!-- 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 --> 
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.
 
User avatar
sfernandez
Site Admin
Posts: 3364
Joined: 22 Dec 2011, 19:20

Re: Memory Leak - An ItemsControl within another ItemsControl?

06 Jul 2022, 11:49

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?
 
lukeyen
Topic Author
Posts: 7
Joined: 22 Dec 2021, 06:00

Re: Memory Leak - An ItemsControl within another ItemsControl?

08 Jul 2022, 07:13

hi @sfernandez
Are you getting memory leak warnings when closing the application? Or why do you think there is a memory leak in this scenario?
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 leaks
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 below

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?
 
User avatar
sfernandez
Site Admin
Posts: 3364
Joined: 22 Dec 2011, 19:20

Re: Memory Leak - An ItemsControl within another ItemsControl?

11 Jul 2022, 17:32

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.
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).
I'll do some tests with that scenario in mind and let you know what I find.
 
User avatar
sfernandez
Site Admin
Posts: 3364
Joined: 22 Dec 2011, 19:20

Re: Memory Leak - An ItemsControl within another ItemsControl?

11 Jul 2022, 18:01

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.
 
lukeyen
Topic Author
Posts: 7
Joined: 22 Dec 2021, 06:00

Re: Memory Leak - An ItemsControl within another ItemsControl?

12 Jul 2022, 22:12

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.
 
User avatar
sfernandez
Site Admin
Posts: 3364
Joined: 22 Dec 2011, 19:20

Re: Memory Leak - An ItemsControl within another ItemsControl?

15 Jul 2022, 11:54

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