-
Notifications
You must be signed in to change notification settings - Fork 24.6k
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
Fix 49958: Close a view leak due to lossy onAnimationEnd callback #49959
base: main
Are you sure you want to change the base?
Conversation
Android's onAnimationEnd callback is lossy and ocasionally just does not fire. However the LayoutAnimationController maintains a sparse array of animations (with Strong View refs) that is only cleaned when the onAnimationEnd callback is invoked. This results in a leak of Android View objects over time. To avoid this, the Strong View refs are migrated to WeakReference's and the associated sparse array is cleaned of any invalid layout animations in response to the reset() call. This closes two leaks: 1. Unbound growth in LayoutAnimationController::mLayoutHandlers 2. Pinning View objects into memory as the sole remaining GC root
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for fixing this!
for (int i = mLayoutHandlers.size() - 1; i >= 0; i--) { | ||
LayoutHandlingAnimation animation = mLayoutHandlers.valueAt(i); | ||
if (!animation.isValid()) { | ||
mLayoutHandlers.removeAt(i); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why shouldn't we fully clear out mLayoutHandlers
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my initial thought as well, but the persistence of Animations across UI operations batch runs (one source of call chain to reset()) almost looks intentional. Because of that, I was worried about unintentionally breaking a non-obvious, yet intentional path in the original implementation.
This down-scoped cleanup will allow Animation objects to persist longer than their useful time but should be safe. A more complete cleanup would remove the Animation objects sooner but at some risk of regression.
@javache has imported this pull request. If you are a Meta employee, you can view this diff on Phabricator. |
Summary:
Android's onAnimationEnd callback is lossy and ocasionally just does not fire. However the LayoutAnimationController maintains a sparse array of animations (with Strong View refs) that is only cleaned when the onAnimationEnd callback is invoked. This results in a leak of Android View objects over time.
To avoid this, the Strong View refs are migrated to WeakReference's and the associated sparse array is cleaned of any invalid layout animations in response to the reset() call.
This closes two leaks:
Changelog:
Pick one each for the category and type tags:
[ANDROID] [Fixed]- Fixes memory leak
Test Plan