Skip to content

Widespread memory leak propagation in visual trees #21809

@AdamEssenmacher

Description

@AdamEssenmacher

Description

Memory leaks in MAUI are exacerbated by orders of magnitude due to their propagation through the visual tree via held references (e.g. Parent, Content, ItemsSource, Children). This leads to entire pages and binding contexts being held in memory indefinitely (sometimes even entire apps), resulting in severe performance degradation, UI choppiness, and eventual forced application shutdowns by the operating system.

I believe this is the most critically severe performance-related issue in MAUI apps today. The behavior is the same across platforms. Lots of effort has been going into fixing individual leaks, but the ROI on these efforts is muted by the all-or-nothing nature of this problem.

Steps to Reproduce

No response

Link to public reproduction project repository

https://github.com/AdamEssenmacher/MemoryToolkit.Maui/tree/main/samples

Version with bug

8.0.7 SR2

Is this a regression from previous behavior?

Yes, this used to work in Xamarin.Forms

Last version that worked well

Unknown/Other

Affected platforms

iOS, Android, Windows, macOS, I was not able test on other platforms

Affected platform versions

No response

Did you find any workaround?

There are three distinct actions that, when applied systemically through the visual tree bottom-up (from leaf to root), can whack leaky views into non-leaking states and compartmentalize small leaks so that they remain isolated to their offending views:

1) Clear the binding context: This contributes to compartmentalization by removing the reference. It also gives the view a chance to reset itself to a near-default state where leaks are least likely to happen (some views only leak in certain states).
2) Clear references to other views: By clearing properties like Content and ItemsSource and calling ClearLogicalChildren(), we can achieve compartmentalization by breaking the visual tree apart.
3) Disconnect (and, if applicable, dispose) the handler: Many handlers are written in such a way that problematic event handlers are only cleaned up when explicitly disconnected.

View Lifecycle Challenges

The workaround I've offered above might not be an ideal or permanent solution. Executing these cleanup measures requires that we have knowledge of when an app is "done with" a given view or page. MAUI currently does not really have a standardized component lifecycle, so there isn't really a central event or hook we can rely on. I have developed an approach that attempts to address this by making an educated guess about when an app is probably "done with" a given Element by checking for these conditions:

  • The Element's Page (or itself, if the Element is a Page) was just popped off the navigation stack.
  • The Element has been unloaded and is not (or no longer) hosted within a Page (e.g. a ControlTemplate that was just swapped out).
  • The Element is hosted within a NavigationPage that has been unloaded

Stopgap Solution

I have developed a behavior that detects leaky views during development using this definition of "done with", and another behavior that automatically applies the cleanup measures described earlier. I offer them as stop-gap measures pending a more robust solution.

Request for Assistance

I encourage the community to provide feedback on these behaviors, and to contribute ideas for how MAUI might incorporate improved lifecycle management to prevent and contain memory leaks.

Relevant log output

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    legacy-area-perfStartup / Runtime performanceperf/generalThe issue affects performance (runtime speed, memory usage, startup time, etc.) (sub: perf)perf/memory-leak 💦Memory usage grows / objects live forever (sub: perf)platform/androidplatform/iosplatform/macosmacOS / Mac Catalystplatform/windowss/triagedIssue has been revieweds/verifiedVerified / Reproducible Issue ready for Engineering Triaget/bugSomething isn't working

    Type

    No type

    Projects

    Status

    Done

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions