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

[android] fix memory leak with CarouselView #18584

Merged
merged 1 commit into from
Nov 8, 2023

Conversation

jonathanpeppers
Copy link
Member

@jonathanpeppers jonathanpeppers commented Nov 7, 2023

Fixes: #17726
Related: #18365

Adding CarouselView to a page and navigating away from it keeps the page alive forever on Android. I was able to reproduce this in a test.

It took me a while to actually track this one down, but the problem boils down to MauiCarouselRecyclerView doing:

_carouselViewLayoutListener = new CarouselViewwOnGlobalLayoutListener();
_carouselViewLayoutListener.LayoutReady += LayoutReady;
ViewTreeObserver.AddOnGlobalLayoutListener(_carouselViewLayoutListener);

The ViewTreeObserver lives longer than the page, and so:

  • ViewTreeObserver -> CarouselViewwOnGlobalLayoutListener
  • event LayoutReady -> MauiCarouselRecyclerView
  • MauiCarouselRecyclerView -> CarouselView
  • CarouselView -> Parent.Parent.Parent.* -> Page

Thus the Page lives forever.

If we remove the LayoutReady event, instead:

  • CarouselViewwOnGlobalLayoutListener saves MauiCarouselRecyclerView in a weak reference.

  • It can just call LayoutReady() directly.

  • MauiCarouselRecyclerView is able to be GC'd now.

  • MauiCarouselRecyclerView.Dispose() already appropriately will call ClearLayoutListener()

  • Lastly, ViewTreeObserver?.RemoveOnGlobalLayoutListener(_carouselViewLayoutListener)

With these changes, the test passes and I don't think anything will leak now. :)

Other changes:

  • I fixed the typo in CarouselViewwOnGlobalLayoutListener.
  • I sorted the type names in the test alphabetically.

Fixes: dotnet#17726

Adding `CarouselView` to a page and navigating away from it keeps the
page alive forever on Android. I was able to reproduce this in a test.

It took me a while to actually track this one down, but the problem
boils down to `MauiCarouselRecyclerView` doing:

    _carouselViewLayoutListener = new CarouselViewwOnGlobalLayoutListener();
    _carouselViewLayoutListener.LayoutReady += LayoutReady;
    ViewTreeObserver.AddOnGlobalLayoutListener(_carouselViewLayoutListener);

The `ViewTreeObserver` lives longer than the page, and so:

* `ViewTreeObserver` -> `CarouselViewwOnGlobalLayoutListener`
* `event LayoutReady` -> `MauiCarouselRecyclerView`
* `MauiCarouselRecyclerView` -> `CarouselView`
* `CarouselView` -> `Parent.Parent.Parent.*` -> `Page`

Thus the `Page` lives forever.

If we remove the `LayoutReady` event, instead:

* `CarouselViewwOnGlobalLayoutListener` saves `MauiCarouselRecyclerView`
in a weak reference.

* It can just call `LayoutReady()` directly.

* `MauiCarouselRecyclerView` is able to be GC'd now.

* `MauiCarouselRecyclerView.Dispose()` already appropriately will call
  `ClearLayoutListener()`

* Lastly, `ViewTreeObserver?.RemoveOnGlobalLayoutListener(_carouselViewLayoutListener)`

With these changes, the test passes and I don't think anything will leak
now. :)

Other changes:

* I fixed the typo in `CarouselViewwOnGlobalLayoutListener`.
* I sorted the type names in the test alphabetically.
{
public EventHandler<EventArgs> LayoutReady;
public void OnGlobalLayout()
class CarouselViewOnGlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
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 made this a nested private class, so it could access the LayoutReady private method.

@jonathanpeppers jonathanpeppers added memory-leak 💦 Memory usage grows / objects live forever platform/android 🤖 labels Nov 7, 2023
@jonathanpeppers jonathanpeppers added this to the .NET 8 + Servicing milestone Nov 7, 2023
@jonathanpeppers jonathanpeppers marked this pull request as ready for review November 7, 2023 22:59
@jonathanpeppers jonathanpeppers requested a review from a team as a code owner November 7, 2023 22:59
@Eilon Eilon added the area-controls-collectionview CollectionView, CarouselView, IndicatorView label Nov 8, 2023
@rmarinho rmarinho merged commit 5d71344 into dotnet:main Nov 8, 2023
47 checks passed
@jonathanpeppers jonathanpeppers deleted the AndroidCarouselViewLeak branch November 8, 2023 13:40
@github-actions github-actions bot locked and limited conversation to collaborators Dec 9, 2023
@samhouts samhouts added the fixed-in-8.0.6 Look for this fix in 8.0.6 SR1! label Aug 2, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-controls-collectionview CollectionView, CarouselView, IndicatorView fixed-in-8.0.6 Look for this fix in 8.0.6 SR1! memory-leak 💦 Memory usage grows / objects live forever platform/android 🤖
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Memory leak with CarouselView
4 participants