maui icon indicating copy to clipboard operation
maui copied to clipboard

Memory leaks on latest .NET 8 preview with Windows

Open symbiogenesis opened this issue 1 year ago • 23 comments

Description

A data grid that I am working on leaks memory massively as you scroll around when there are a lot of records.

Steps to Reproduce

Just run the sample I provided, and start scrolling, etc.

Link to public reproduction project repository

https://github.com/symbiogenesis/Maui.DataGrid/tree/net8-memory-leak

Version with bug

8.0.0-preview.6.8686

Last version that worked well

Unknown/Other

Affected platforms

Windows

Affected platform versions

All

Did you find any workaround?

No.

Relevant log output

No response

symbiogenesis avatar Jul 29 '23 22:07 symbiogenesis

@jonathanpeppers You may have some thoughts. Manually running GC doesn't help.

symbiogenesis avatar Jul 29 '23 23:07 symbiogenesis

Everywhere you see += with an event in this file is a potential leak:

https://github.com/symbiogenesis/Maui.DataGrid/blob/net8-memory-leak/Maui.DataGrid/DataGrid.xaml.cs

So far looking at this, I see several potential leaks in this DataGrid control. It's probably not worth looking if there are further MAUI issues here without those solved.

Have you seen this wiki page? It might help you diagnose and track these down:

  • https://github.com/dotnet/maui/wiki/Memory-Leaks

jonathanpeppers avatar Aug 03 '23 22:08 jonathanpeppers

My code is already using the WeakEventManager for all of my events, and I unsubscribe to all of the events at what I think is the proper times, with the exception of a minor change I just made.

Not sure what else I ought to be doing. That link shows some similar event usage, and links to a PR that implements the WeakEventManager approach that I'm already using.

symbiogenesis avatar Aug 05 '23 07:08 symbiogenesis

I think I see now. So the subscriptions to events that are located outside of MAUI in the .NET Framework are unsafe, and need a proxy wrapper to make them safe.

I will implement that and try again.

symbiogenesis avatar Aug 07 '23 15:08 symbiogenesis

I just implemented that in the linked branch, except where WeakEventManager was being used, and the memory leaks remain

symbiogenesis avatar Aug 07 '23 17:08 symbiogenesis

Especially on Windows, you should be able to see a tree of objects from a memory snapshot. What object is holding on to another object? If you can share their fully qualified name or the .gcdump file that would make things clearer.

In addition to the Narrowing down the leak instructions:

https://github.com/dotnet/maui/wiki/Memory-Leaks#narrowing-down-the-leak

Does the problem go away if you swap your custom DataGrid control with something built-in? Like a ListView or CollectionView?

jonathanpeppers avatar Aug 07 '23 18:08 jonathanpeppers

image

image

symbiogenesis avatar Aug 07 '23 18:08 symbiogenesis

Can you address the XAML hot reload warning in your screenshot?

We mention it on the wiki page:

image

Did you also sprinkle some GC.Collect() calls in the app as mentioned?

image

jonathanpeppers avatar Aug 07 '23 19:08 jonathanpeppers

I had tried using GC.Collect() in the app before, to no effect. Just tried now, and there was no effect.

Just tried turning off XAML Hot Reload, and it had no effect.

Also removed the more complicated columns and just kept some simple text columns. And the leak remains.

image

symbiogenesis avatar Aug 07 '23 20:08 symbiogenesis

Can you comment on:

Does the problem go away if you swap your custom DataGrid control with something built-in? Like a ListView or CollectionView?

Your latest screenshot shows the DataGrid, but what is the exact object you think is leaking? So far, what I see are problems in this DataGrid control.

jonathanpeppers avatar Aug 07 '23 21:08 jonathanpeppers

The DataGrid control is mainly a wrapper for the CollectionView. Each row is a Grid, with identical ColumnDefinitions.

I personally think that the CollectionView is leaking.

symbiogenesis avatar Aug 07 '23 21:08 symbiogenesis

Changing the CollectionView to a ListView does not resolve the problem.

symbiogenesis avatar Aug 07 '23 23:08 symbiogenesis

Can you share a branch of your sample that uses ListView or CollectionView?

https://github.com/symbiogenesis/Maui.DataGrid/tree/net8-memory-leak

It isn't using the DataGrid at all, correct?

jonathanpeppers avatar Aug 07 '23 23:08 jonathanpeppers

I just updated this branch to just use a simple CollectionView, and the ListView version is commented out below it.

With this simple version, it also leaks, yes.

symbiogenesis avatar Aug 07 '23 23:08 symbiogenesis

Specifically, I think it is only when using an ItemTemplate, and this issue has existed since Xamarin.Forms

symbiogenesis avatar Aug 07 '23 23:08 symbiogenesis

I found this issue with ListView: https://github.com/dotnet/maui/issues/16450#issuecomment-1670166956

But let me see if something similar is happening with CollectionView as that seems more important. (It's the new control you're supposed to use)

jonathanpeppers avatar Aug 08 '23 21:08 jonathanpeppers

This might have more to do with the Grid being inside of the ItemTemplate, rather than the ItemTemplate in general.

symbiogenesis avatar Aug 08 '23 23:08 symbiogenesis

@symbiogenesis I did some debugging, and it appears the way the CollectionView works.

  1. You have 150,000 rows, it apparently creates a List<ItemTemplateContext> with 150,000 null items...
  2. This code is called as each row is scrolled into view:

https://github.com/dotnet/maui/blob/040f2f13c389a2092d03287bd794888704f33cae/src/Controls/src/Core/Platform/Windows/CollectionView/ItemTemplateContextList.cs#L25-L29

And so ItemTemplateContext instances will grow as you scroll each one into view. I did not see the memory growing when I scroll to rows that were already on screen:

image

Now, I do see some things in the code here that could be improved -- but I'm not seeing a leak so far.

Do you feel like you are seeing something different than me? I will see if ListView feels any different.

jonathanpeppers avatar Aug 17 '23 19:08 jonathanpeppers

One reason that I think it leaks is that navigating away from the page doesn't free up any memory. Even with a manual garbage collect.

I also tend to use more complicated DataTemplates, and with these scrolling back to rows that were already loaded does increase the memory usage.

symbiogenesis avatar Aug 17 '23 20:08 symbiogenesis

navigating away from the page doesn't free up any memory I also tend to use more complicated DataTemplates

Can you update the sample to show this behavior? Or some examples of DataTemplate that leak?

I tried ListView, but it also seems OK when this change (merged today) is in place: 040f2f13c389a2092d03287bd794888704f33cae

image

I opened this one, as an obvious improvement looking at the existing code:

  • https://github.com/dotnet/maui/pull/16838

jonathanpeppers avatar Aug 17 '23 21:08 jonathanpeppers

I created a simple project, specified this XAML and using mouse scrolling up and down, you can increase memory consumption to over 3 gigabytes

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Sample.MultipleButtonsPage"
             Title="test">
    <StackLayout>
        <CollectionView x:Name="collectionView"
                        ItemSizingStrategy="MeasureFirstItem"
                        VerticalOptions="FillAndExpand">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <ContentView Padding="10">
                        <Label Text="{Binding .}"/>
                    </ContentView>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </StackLayout>
</ContentPage>

(ItemsSource is simple List with 1000 elements) LOL

scriptBoris avatar Jan 26 '24 16:01 scriptBoris

NET8, Controls nuget lib version 8.0.6

scriptBoris avatar Jan 26 '24 16:01 scriptBoris

@scriptBoris I see the same thing as you. I just submitted PR https://github.com/dotnet/maui/pull/20036 that may help a bit with CollectionView on Windows. I'm sure there's lots more to do.

symbiogenesis avatar Jan 26 '24 17:01 symbiogenesis

Verified this issue with Visual Studio Enterprise 17.10.0 Preview 1. Can repro on Windows platform with sample project. I disabled XAML Hot Reload, and after successful debugging, I scrolled up and down, but the problem still occurred. https://github.com/symbiogenesis/Maui.DataGrid/tree/net8-memory-leak image

Zhanglirong-Winnie avatar Feb 20 '24 07:02 Zhanglirong-Winnie

Here is a sample where you can reproduce the issue. Run the application and click on the "Reload Data" button. On every data load, you will see that memory consumption is increasing. The sample contains a simple data template with a grid.

kaushik-sarker avatar Mar 08 '24 05:03 kaushik-sarker