Skip to content

[android] fix memory leak with CarouselView#18584

Merged
rmarinho merged 1 commit intodotnet:mainfrom
jonathanpeppers:AndroidCarouselViewLeak
Nov 8, 2023
Merged

[android] fix memory leak with CarouselView#18584
rmarinho merged 1 commit intodotnet:mainfrom
jonathanpeppers:AndroidCarouselViewLeak

Conversation

@jonathanpeppers
Copy link
Copy Markdown
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
Copy Markdown
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 perf/memory-leak 💦 Memory usage grows / objects live forever (sub: perf) 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
@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! perf/memory-leak 💦 Memory usage grows / objects live forever (sub: perf) platform/android

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Memory leak with CarouselView

4 participants