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

[ios/catalyst] fix memory leak in ToolbarItem #22893

Merged
merged 1 commit into from
Jun 7, 2024

Conversation

jonathanpeppers
Copy link
Member

Fixes: #22814

ToolbarItem has a circular reference that causes it to live forever:

  • ToolbarItem -> ToolbarItemExtensions.PrimaryToolbarItem -> ToolbarItem

And then if you have a Page such as:

class LeakyShellPage : ContentPage
{
    public LeakyShellPage()
    {
        var item = new ToolbarItem { Text = "Primary Item" };
        item.Clicked += OnToolbarItemClicked;
        ToolbarItems.Add(item);
    }

    // Needs to be an instance method
    void OnToolbarItemClicked(object sender, EventArgs e) { }
}

Then the ToolbarItem (that leaks), would also cause the entire Page to leak as it has a strong reference to it. I could reproduce this problem by updating a tests in ShellTests.cs to add a ToolbarItem.

To solve this problem, I changed the _item field in both PrimaryToolbarItem and SecondaryToolbarItem to be a WeakReference.

While writing tests, I found there was a mismatched #if and #endif.

I think part of ShellTests.cs were not running at all on MACCATALYST by accident. So, I hope they still pass?

Fixes: dotnet#22814

`ToolbarItem` has a circular reference that causes it to live forever:

* `ToolbarItem` -> `ToolbarItemExtensions.PrimaryToolbarItem` -> `ToolbarItem`

And then if you have a `Page` such as:

    class LeakyShellPage : ContentPage
    {
        public LeakyShellPage()
        {
            var item = new ToolbarItem { Text = "Primary Item" };
            item.Clicked += OnToolbarItemClicked;
            ToolbarItems.Add(item);
        }

        // Needs to be an instance method
        void OnToolbarItemClicked(object sender, EventArgs e) { }
    }

Then the `ToolbarItem` (that leaks), would also cause the entire `Page`
to leak as it has a strong reference to it. I could reproduce this
problem by updating a tests in `ShellTests.cs` to add a `ToolbarItem`.

To solve this problem, I changed the `_item` field in both
`PrimaryToolbarItem` and `SecondaryToolbarItem` to be a `WeakReference`.

While writing tests, I found there was a mismatched `#if` and `#endif`.

I think part of `ShellTests.cs` were not running at all on `MACCATALYST`
by accident. So, I hope they still pass?
@@ -82,6 +82,7 @@ public async Task PageLayoutDoesNotExceedWindowBounds()
Assert.True(pageBounds.Height <= window.Height);
});
}
#endif
Copy link
Member Author

@jonathanpeppers jonathanpeppers Jun 6, 2024

Choose a reason for hiding this comment

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

I think this accidentally put #if !MACCATALYST across this entire file. 👀 Might have been a merge conflict?

@jonathanpeppers jonathanpeppers added the memory-leak 💦 Memory usage grows / objects live forever (sub: perf) label Jun 6, 2024
@jonathanpeppers jonathanpeppers marked this pull request as ready for review June 7, 2024 04:50
@jonathanpeppers jonathanpeppers requested a review from a team as a code owner June 7, 2024 04:50

Clicked += (sender, e) => ((IMenuItemController)_item).Activate();
Clicked += OnClicked;
Copy link
Member Author

Choose a reason for hiding this comment

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

I couldn't change this to:

Suggested change
Clicked += OnClicked;
Clicked += (sender, e) => ((IMenuItemController)item).Activate();;

This created a closure on item that also leaked.

@PureWeen PureWeen merged commit 4e12cee into dotnet:main Jun 7, 2024
49 checks passed
@github-actions github-actions bot locked and limited conversation to collaborators Jul 8, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
fixed-in-8.0.60 fixed-in-9.0.0-preview.6.24327.7 memory-leak 💦 Memory usage grows / objects live forever (sub: perf)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[ios] ContentPage.ToolbarItems is not currently being Garbage Collected (clicked event handler used)
3 participants