Skip to content

[iOS]Fix: FlyoutPage memory leak #28769

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

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

bhavanesh2001
Copy link
Contributor

Description of Change

While enabling the UITest Bugzilla31255Test, which pushes a FlyoutPage modally and then pops it, I encountered a memory leak on iOS. The FlyoutPage instance was not being collected even after the modal pop.

Originally, the test case was also causing a crash because Flyout and Detail were being set to instances of Page, which is not supported. I updated them to use ContentPage, which resolved the crash.

The memory leak was caused by the renderer holding a strong reference to the virtual view (_element), which prevented the FlyoutPage from being garbage collected.

I also added a device test that reproduces the same modal flow and asserts that the page is collected by the GC. While this device test covers the same scenario as the UITest, I’ve kept both for now.

If you'd prefer to remove the UITest and rely only on the device test, let me know.

Before Fix After Fix
Screenshot 2025-04-02 at 9 17 03 PM Screenshot 2025-04-02 at 9 19 11 PM

Issues Fixed

Fixes #21206

@bhavanesh2001 bhavanesh2001 requested a review from a team as a code owner April 2, 2025 16:20
Copy link
Contributor

Hey there @@bhavanesh2001! Thank you so much for your PR! Someone from the team will get assigned to your PR shortly and we'll get it reviewed.

@dotnet-policy-service dotnet-policy-service bot added the community ✨ Community Contribution label Apr 2, 2025
@@ -269,9 +270,7 @@ protected override void Dispose(bool disposing)
}

EmptyContainers();

Page.SendDisappearing();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't be here. We are already calling this above

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it matter if we just leave it?

Copy link
Contributor Author

@bhavanesh2001 bhavanesh2001 Apr 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PureWeen Without the PR changes, since we’re inside Dispose, the wrapper’s Element will be null at this point — so Page falls back to the strongly referenced _element:

public VisualElement Element => _viewHandlerWrapper.Element ?? _element;

With the PR changes, _element is resolved through a weak reference, so keeping the SendDisappearing() call here won’t make a difference

Let me know if you think I should keep the call.

@PureWeen PureWeen added this to the .NET 9 SR7 milestone Apr 2, 2025
{
App.Screenshot("I am at Bugzilla 31255");
await Task.Delay(5000);
App.WaitForNoElement("Page1. But Page2 IsAlive = False");
Thread.Sleep(5000);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test is probably going to be flaky as-is (possible to fail at some percentage), best results are to do something like these other tests:

await Task.Yield();
GC.Collect();
GC.WaitForPendingFinalizers();

@PureWeen is there a helper method for this in the UITests project?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonathanpeppers checking for memory leaks in a UI test isn’t really ideal and not something we typically do. That’s exactly why I added a device test that covers the same modal FlyoutPage scenario.

I’ve still kept the UI test for now just because it was already there and passing with the fix, but I think we can safely remove it if we’re good with the device test coverage.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@PureWeen is there a helper method for this in the UITests project?

Recently, there was this attempt https://github.com/dotnet/maui/pull/28489/files by @simonrozsival. Hopefully, it will get resurrected. :)

@jsuarezruiz jsuarezruiz added memory-leak 💦 Memory usage grows / objects live forever (sub: perf) platform/iOS 🍎 labels Apr 4, 2025
@jsuarezruiz
Copy link
Contributor

/azp run

Copy link

Azure Pipelines successfully started running 3 pipeline(s).

@bhavanesh2001
Copy link
Contributor Author

The UI test is passing, but the device test failed on Android and Windows. It seems the issue was with the test itself, so I’ve modified it accordingly.
Screenshot 2025-04-04 at 7 16 40 PM
Screenshot 2025-04-04 at 7 17 03 PM
@jsuarezruiz

@bhavanesh2001
Copy link
Contributor Author

/rebase

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-controls-flyoutpage FlyoutPage community ✨ Community Contribution memory-leak 💦 Memory usage grows / objects live forever (sub: perf) platform/iOS 🍎
Projects
Status: Todo
Development

Successfully merging this pull request may close these issues.

[Testing] Crash popping FlyoutPage
6 participants