maui icon indicating copy to clipboard operation
maui copied to clipboard

[controls] fix memory leak in `Window`

Open jonathanpeppers opened this issue 3 years ago • 6 comments

Fixes: https://github.com/dotnet/maui/issues/10029

I could reproduce a memory leak by doing:

App.Current.OpenWindow(new Window { Page = new ContentPage() });

I found that App.Current._requestedWindows just held onto every Window object forever.

This is a perfect example of where using ConditionalWeakTable solves the issue:

https://learn.microsoft.com/dotnet/api/system.runtime.compilerservices.conditionalweaktable-2

The only other change I made was to use Guid.ToString("n") as it removes {, }, and - characters from the string.

After these changes, I still found Window objects hanging around that appeared to be held onto by many other objects.

Then I reviewed:

void IWindow.Destroying()
{
    SendWindowDisppearing();
    Destroying?.Invoke(this, EventArgs.Empty);
    OnDestroying();

    Application?.RemoveWindow(this);
    // This wasn't here!
    Handler?.DisconnectHandler();
}

It appears that upon Window's closing, we didn't have any code that "disconnected" the MAUI handler. After this change, I could see Window objects properly go away.

I added a unit test as well.

jonathanpeppers avatar Feb 16 '23 16:02 jonathanpeppers

/azp run

rmarinho avatar Feb 16 '23 21:02 rmarinho

Azure Pipelines successfully started running 2 pipeline(s).

azure-pipelines[bot] avatar Feb 16 '23 21:02 azure-pipelines[bot]

This might cause a test failure on iOS:

image

jonathanpeppers avatar Feb 23 '23 15:02 jonathanpeppers

Can repro the test failure locally, I can say that I am a bit confused:

shot

There might be an issue in this test, will look into it.

jonathanpeppers avatar Feb 23 '23 21:02 jonathanpeppers

Ok the test uses async void to do work:

https://github.com/dotnet/maui/blob/53f6e393750a3df05b12fcde442daf3616c216f8/src/Controls/tests/DeviceTests/Elements/Window/WindowTests.cs#L125

xunit is moving on as if the test passed, but test code is continuing to run.

Will review if we have a better way to do this.

jonathanpeppers avatar Feb 23 '23 21:02 jonathanpeppers

Will come back to this after this one lands:

https://github.com/dotnet/maui/pull/13536

jonathanpeppers avatar Feb 23 '23 22:02 jonathanpeppers

/backport to net7.0

PureWeen avatar Mar 02 '23 15:03 PureWeen

Started backporting to net7.0: https://github.com/dotnet/maui/actions/runs/4315741361

github-actions[bot] avatar Mar 02 '23 15:03 github-actions[bot]

@PureWeen backporting to net7.0 failed, the patch most likely resulted in conflicts:

$ git am --3way --ignore-whitespace --keep-non-patch changes.patch

Applying: [controls] fix memory leak in `Window`
Using index info to reconstruct a base tree...
M	src/Controls/src/Core/HandlerImpl/Application/Application.Impl.cs
M	src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs
M	src/Controls/tests/Core.UnitTests/WindowsTests.cs
Falling back to patching base and 3-way merge...
Auto-merging src/Controls/tests/Core.UnitTests/WindowsTests.cs
CONFLICT (content): Merge conflict in src/Controls/tests/Core.UnitTests/WindowsTests.cs
Auto-merging src/Controls/src/Core/HandlerImpl/Window/Window.Impl.cs
Auto-merging src/Controls/src/Core/HandlerImpl/Application/Application.Impl.cs
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
Patch failed at 0001 [controls] fix memory leak in `Window`
When you have resolved this problem, run "git am --continue".
If you prefer to skip this patch, run "git am --skip" instead.
To restore the original branch and stop patching, run "git am --abort".
Error: The process '/usr/bin/git' failed with exit code 128

Please backport manually!

github-actions[bot] avatar Mar 02 '23 15:03 github-actions[bot]

@PureWeen an error occurred while backporting to net7.0, please check the run log for details!

Error: git am failed, most likely due to a merge conflict.

github-actions[bot] avatar Mar 02 '23 15:03 github-actions[bot]