Fix: CurvedAnimation instances not disposed (fixes #155)#166
Open
winter-cw wants to merge 1 commit into
Open
Conversation
Replace CurvedAnimation with CurveTween + Animation.drive to avoid creating disposable objects during the build phase that are never disposed, which causes memory leaks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix: CurvedAnimation instances not disposed (fixes #155)
Reported by @raulmabe-labhouse in #155
Problem
EffectEntry.buildAnimation()creates a newCurvedAnimationon every call:CurvedAnimationis a disposable object — it registers itself as a listener on the parentAnimationControllerand must be explicitly.dispose()d to unregister. However,buildAnimation()is called fromEffect.build(), which is invoked during_AnimateState.build(). This means a newCurvedAnimationis allocated on every widget rebuild, and none of them are ever disposed.The
_AnimateState.dispose()method only disposes theAnimationController— disposing the controller does not dispose childCurvedAnimationinstances attached to it.How we found it
We integrated Dart's leak_tracker package into our production Flutter app with
collectStackTraceOnStart: trueenabled, which captures creation stack traces for every tracked object. During a typical user session navigating through multiple screens, we observedCurvedAnimationas one of the top leaked types, with all creation stack traces pointing toEffectEntry.buildAnimationinflutter_animate.In a single exploration session across ~15 screens, we measured 62 leaked
CurvedAnimationinstances fromflutter_animatealone. After applying this fix, that number dropped to 0 — the remainingCurvedAnimationleaks in the report were all from Flutter framework internals (overscroll glow, FAB transitions, implicit animations).Fix
Replace
CurvedAnimationwithCurveTween+Animation.drive():Both produce the same
Animation<double>applying the same curve. The difference:CurvedAnimation(parent: controller, curve: ...)— creates a disposable object that registers as a listener on the parent controller. Must be explicitly disposed.controller.drive(CurveTween(curve: ...))— returns a non-disposable_AnimatedEvaluationthat evaluates the tween lazily on each frame. No listener registration, no disposal needed.Since
buildAnimation()is called insidebuild()— where there is no corresponding lifecycle hook to dispose the result —CurveTween+.drive()is the correct pattern. This is consistent with Flutter's own documentation recommending.drive()overCurvedAnimationwhen the animation is created in contexts without disposal management.Impact
Every
Animatewidget with effects (fade, slide, scale, etc.) leaks oneCurvedAnimationper effect per widget lifecycle. In apps that useflutter_animateextensively (143 files in our codebase), this adds up to hundreds of undisposed objects during a typical user session, holding references to animation controllers and preventing proper garbage collection.Tests
All 52 existing tests pass with no changes required — the fix is API-compatible and produces identical animation behavior.
🤖 Generated with Claude Code