Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leak in RadioButton ControlTemplate #23199

Closed
krdmllr opened this issue Jun 23, 2024 · 10 comments
Closed

Memory leak in RadioButton ControlTemplate #23199

krdmllr opened this issue Jun 23, 2024 · 10 comments
Assignees
Labels
area-controls-radiobutton RadioButton, RadioButtonGroup memory-leak 💦 Memory usage grows / objects live forever (sub: perf) p/2 Work that is important, but is currently not scheduled for release platform/windows 🪟 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Milestone

Comments

@krdmllr
Copy link
Contributor

krdmllr commented Jun 23, 2024

Description

Hi,
we found that when refreshing a list which contains customized RadioButtons, hundreds of Ellipse objects from the template remain in memory.
I created a sample repo which just uses the control template from the maui documentation https://learn.microsoft.com/en-us/dotnet/maui/user-interface/controls/radiobutton?view=net-maui-8.0#redefine-radiobutton-appearance

When refreshing the list a few times, doing GC.Collects in between and taking a snapshot just using Visual Studio, I found the same issue occuring in the sample repo:
image

Same behavior happens with a Release build + JetBrains dotMemory in our production app.

Steps to Reproduce

  1. Start app
  2. Click "Recreate List" button, this does a GC.Collect(), clears and fills the list again

Link to public reproduction project repository

https://github.com/krdmllr/MauiMemoryLeaks

Version with bug

8.0.60 SR6

Is this a regression from previous behavior?

Not sure, did not test other versions

Last version that worked well

Unknown/Other

Affected platforms

Windows

Affected platform versions

windows 10.0.19041.0

Did you find any workaround?

No response

Relevant log output

No response

@krdmllr krdmllr added the t/bug Something isn't working label Jun 23, 2024
Copy link
Contributor

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Open similar issues:

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

@MartyIX MartyIX added platform/windows 🪟 memory-leak 💦 Memory usage grows / objects live forever (sub: perf) area-controls-radiobutton RadioButton, RadioButtonGroup labels Jun 23, 2024
@RoiChen001 RoiChen001 added s/verified Verified / Reproducible Issue ready for Engineering Triage s/triaged Issue has been reviewed labels Jun 24, 2024
@RoiChen001
Copy link

I can repro this issue at Windows platform on the latest 17.11.0 Preview 2.1(8.0.60).

@PureWeen PureWeen added the p/2 Work that is important, but is currently not scheduled for release label Jun 24, 2024
@PureWeen PureWeen added this to the Backlog milestone Jun 24, 2024
@Foda Foda self-assigned this Jun 25, 2024
jonathanpeppers added a commit to jonathanpeppers/maui that referenced this issue Jun 26, 2024
Somehow these pass, but the sample here has an issue:

* dotnet#23199

Past links related to `RadioButton`:

* dotnet#18365
* dotnet#21151
jonathanpeppers added a commit to jonathanpeppers/maui that referenced this issue Jun 27, 2024
Somehow these pass, but the sample here has an issue:

* dotnet#23199

Past links related to `RadioButton` leaks:

* dotnet#18365
* dotnet#21151
jonathanpeppers added a commit to jonathanpeppers/maui that referenced this issue Jun 27, 2024
Somehow these pass, but the sample here has an issue:

* dotnet#23199

After further investigation, I'm not sure there is an actual issue.

Past links related to `RadioButton` leaks:

* dotnet#18365
* dotnet#21151
@jonathanpeppers
Copy link
Member

After deeper investigation, I don't think I'm seeing a problem here on Windows.

First, I would recommend these changes in the sample to test this:

The sample was calling ObservableCollection.Add() over and over, which is not the best for performance. It can be a bit better to replace the entire collection in one go.

With this change, I see memory being pretty stable and going up and down, even if I click "Recreate List" very quickly:

image

I don't see extra Ellipse instances alive here.

To be sure there wasn't a problem, I wrote a couple new tests in .NET MAUI, but they pass successfully:

Let me know if I missed something, or if I should try a different platform. Thanks!

jonathanpeppers added a commit to jonathanpeppers/maui that referenced this issue Jun 27, 2024
This expands the tests to cover more controls and areas.

* Add test cases for more controls:

  * `Ellipse`
  * `Grid`
  * `Path`
  * `Line`
  * `Path`
  * `RadioButton`
  * `Rectangle`
  * `RoundRectangle`

* Expand tests for a couple controls:

    * `Border` has a `StrokeShape`
    * Any `TemplatedView` gets a `ControlTemplate`

* Re-enable `ListView` for Android

This should work now after merging:

* dotnet/android#8900
* dotnet#23120

* Add a complicated test case for `BindableLayout`

Similar to the case at:

* dotnet#23199
@krdmllr
Copy link
Contributor Author

krdmllr commented Jun 27, 2024

Hi, thank you very much for taking a look!

I will retest that in our environment to see if anything changes.

We replace the whole collection and just use an array instead of ObservableCollection in our app. However, we also use a lot of rx with DynamicData where we filter and sort lists and bind them using ReadOnlyObservableCollections. They use Reset when swapping larger collections. Would you generally recommend to change that to replace the collections instead?

@jonathanpeppers
Copy link
Member

The main thing to check is that an event fires once, instead of ObservableCollection.CollectionChanged firing 1-per item.

In my example, it was actually OnPropertyChanged(nameof(Items)) that refreshed the screen.

PureWeen pushed a commit that referenced this issue Jun 28, 2024
* [tests] test a lot more things in `MemoryTests.cs`

This expands the tests to cover more controls and areas.

* Add test cases for more controls:

  * `Ellipse`
  * `Grid`
  * `Path`
  * `Line`
  * `Path`
  * `RadioButton`
  * `Rectangle`
  * `RoundRectangle`

* Expand tests for a couple controls:

    * `Border` has a `StrokeShape`
    * Any `TemplatedView` gets a `ControlTemplate`

* Re-enable `ListView` for Android

This should work now after merging:

* dotnet/android#8900
* #23120

* Add a complicated test case for `BindableLayout`

Similar to the case at:

* #23199

* Skip `ListView` on API 23
@krdmllr
Copy link
Contributor Author

krdmllr commented Jun 29, 2024

Can confirm that calling GC more often shows that the object count stays at 80 ellipses.

The overall memory consumption still increases when reloading the data, is that something that is expected?

image

mattleibow added a commit that referenced this issue Jul 1, 2024
* Simplify Development.md (#23142)

* Simplify Development.md

* Update .github/DEVELOPMENT.md

Co-authored-by: Eilon Lipton <[email protected]>

* Update .github/DEVELOPMENT.md

Co-authored-by: Eilon Lipton <[email protected]>

* Update .github/DEVELOPMENT.md

Co-authored-by: Eilon Lipton <[email protected]>

* Update .github/DEVELOPMENT.md

Co-authored-by: Eilon Lipton <[email protected]>

* Update DEVELOPMENT.md

* - modify and move advanced tips to different file

* Update DEVELOPMENT.md

* Update .github/DEVELOPMENT.md

Co-authored-by: Gerald Versluis <[email protected]>

* Update docs/DevelopmentTips.md

Co-authored-by: Gerald Versluis <[email protected]>

* Update docs/DevelopmentTips.md

Co-authored-by: Gerald Versluis <[email protected]>

* - updates based on review

---------

Co-authored-by: Eilon Lipton <[email protected]>
Co-authored-by: Gerald Versluis <[email protected]>

* Wire RefreshView up to our xplat layout workflow (#23169) (#23218)

* Use better layout/measure path with refreshview

* - fix naming

* - set RefreshView content to maui compatible container

* - add test

* - fix null operator

* Update Issue23029.xaml.cs

* - fix content panel so it removes previous content

* - add additional check

* Remove adding to FutureAccessList as the app is running with runFullTrust capability (#23047)

* Call base.OnResume if Existing NavigationFragment Early (#23187)

* VSCode no longer uses MAUI to launch (#23222)

* [Android] Fix flyout behaviour switching exception (#22453)

* Fix flyout behaviour switching exception

* Tests added

* Flyout test page added

* Flyoutpage test fixes

* Flyout toggle test added

* Remove duplicate ] characters

* Flyout test pages added

* Check for platforms

* Fix title

* - fix tests

---------

Co-authored-by: Gerald Versluis <[email protected]>
Co-authored-by: Shane Neuville <[email protected]>

* Renamed the project because macOS uses .app (#23223)

* Renamed the project because macOS uses .app

* And the folder

* merge first

* ns

* Move tests to new location (#23251)

* Split SingleProject targets (#23269)

* Split SingleProject targets

* Update Microsoft.Maui.Controls.SingleProject.Before.targets

* Update bug-report.yml with 8.0.61 (#23273)

* Null terminate Page on TabbedRenderer (#23290)

Co-authored-by: Shane Neuville <[email protected]>

* [Windows] Improve performance in accessibility extensions (#22698)

* AccessibilityExtensions: Add missing braces

* AccessibilityExtensions: Enable nullability and improve performance

* Update shipped & unshipped API

---------

Co-authored-by: Javier Suárez <[email protected]>

* [Android] Avoid double event subscribes in gesture manager (#23242)

* [Android] Avoid double event subscribes in gesture manager

* Fix typo in test text

* Bump Microsoft.Web.WebView2 from 1.0.2151.40 to 1.0.2592.51 (#23209)

* [tests] test a lot more things in `MemoryTests.cs` (#23324)

* [tests] test a lot more things in `MemoryTests.cs`

This expands the tests to cover more controls and areas.

* Add test cases for more controls:

  * `Ellipse`
  * `Grid`
  * `Path`
  * `Line`
  * `Path`
  * `RadioButton`
  * `Rectangle`
  * `RoundRectangle`

* Expand tests for a couple controls:

    * `Border` has a `StrokeShape`
    * Any `TemplatedView` gets a `ControlTemplate`

* Re-enable `ListView` for Android

This should work now after merging:

* dotnet/android#8900
* #23120

* Add a complicated test case for `BindableLayout`

Similar to the case at:

* #23199

* Skip `ListView` on API 23

* Bump Appium version to 2.11 (#23337)

* Bump Appium version to 2.11

* Update CarouselViewUITests.UpdateCurrentItem.cs

* Update appium-install.ps1

* Update CarouselViewUITests.UpdateCurrentItem.cs

* Simplify `NavigationRootManager.Connect` on the Windows platform. (#23345)

* Simplify `NavigationRootManager.Connect` on the Windows platform.

* Use ternary operator syntax

* Removed extra tabs

* Moved `_disconnected = false;` to `if (_disconnected)`

* Bump Appium Drivers (#23349)

* Fix Merge

---------

Co-authored-by: Eilon Lipton <[email protected]>
Co-authored-by: Gerald Versluis <[email protected]>
Co-authored-by: MartyIX <[email protected]>
Co-authored-by: Matthew Leibowitz <[email protected]>
Co-authored-by: Thomas Muller <[email protected]>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Javier Suárez <[email protected]>
Co-authored-by: Jonathan Dick <[email protected]>
Co-authored-by: Jonathan Peppers <[email protected]>
Co-authored-by: Takym (たかやま) <[email protected]>
@jonathanpeppers
Copy link
Member

If you are always seeing 80, it's probably not a leak. It just means that it takes a few GCs for them to go away. A leak would mean 80->100->120 that continuously grows.

In my screenshot above, if I let the app "rest" for a second, that is what caused this drop to appear:

image

If you are testing and see something different than me, see if you can find out which object type is growing. I can take another look in that case, thanks!

@krdmllr
Copy link
Contributor Author

krdmllr commented Jul 1, 2024

If you are always seeing 80, it's probably not a leak. It just means that it takes a few GCs for them to go away. A leak would mean 80->100->120 that continuously grows.

Yes, I see that the ellipse is not leaking like I suggested initially, I have the same results after adding the additional GC calls. I was wondering why the heap size is still increasing between the snapshots (+200kb in my snapshot), should it not go back to 0 increase or even decrease when calling GC manually?

@jonathanpeppers
Copy link
Member

For me, it was going down (lower than a previous collection) as I waited longer & clicked longer. There was a stable point the memory usage would hover around.

If you see it going up, diff a few snapshots to see if you can figure out what object (full namespace + type) is the cause.

@krdmllr
Copy link
Contributor Author

krdmllr commented Jul 1, 2024

@jonathanpeppers thank you, I will close the issue for now and raise a new one if necessary.

@krdmllr krdmllr closed this as not planned Won't fix, can't repro, duplicate, stale Jul 1, 2024
@github-actions github-actions bot locked and limited conversation to collaborators Aug 1, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-controls-radiobutton RadioButton, RadioButtonGroup memory-leak 💦 Memory usage grows / objects live forever (sub: perf) p/2 Work that is important, but is currently not scheduled for release platform/windows 🪟 s/triaged Issue has been reviewed s/verified Verified / Reproducible Issue ready for Engineering Triage t/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants