Skip to content

Conversation

chunhtai
Copy link
Contributor

fixes #126100

Pre-launch Checklist

  • I read the Contributor Guide and followed the process outlined there for submitting PRs.
  • I read the Tree Hygiene wiki page, which explains my responsibilities.
  • I read and followed the Flutter Style Guide, including Features we expect every widget to implement.
  • I signed the CLA.
  • I listed at least one issue that this PR fixes in the description above.
  • I updated/added relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or this PR is test-exempt.
  • All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel on Discord.

@flutter-dashboard flutter-dashboard bot added f: material design flutter/packages/flutter/material repository. f: routes Navigator, Router, and related APIs. framework flutter/packages/flutter repository. See also f: labels. labels May 10, 2023
if (toRoute != fromRoute && toRoute is PageRoute<dynamic> && fromRoute is PageRoute<dynamic>) {
final PageRoute<dynamic> from = fromRoute;
final PageRoute<dynamic> to = toRoute;
if (toRoute == fromRoute) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this just refactor the if condition to return early instead of nested condition.

the real functional change is in line 889 where it check for whether the route is still active before actually do the fly.

@chunhtai chunhtai requested a review from goderbauer May 10, 2023 18:33
@goderbauer
Copy link
Member

Looks like many checks are failing. is that related to this change?

if (toRoute == fromRoute) {
return;
}
if (toRoute is! PageRoute<dynamic> || fromRoute is! PageRoute<dynamic>) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you combine this with the previous if?

@@ -214,7 +214,9 @@ class OverlayEntry implements Listenable {
/// This method should only be called by the object's owner.
void dispose() {
assert(!_disposedByOwner);
assert(_overlay == null, 'An OverlayEntry must first be removed from the Overlay before dispose is called.');
// In case the owner of this Overlay
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this comment seems to be incomplete?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not immediately clear to me why the mounted state of the overlay is relevant. I guess that may have been what this comment was supposed to be about?

Copy link
Contributor Author

@chunhtai chunhtai May 11, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sorry about this, I should have turn this into draft. The mounted state was because if the owner of this overlay entry is above the overlay widget. It is possible the entry will be disposed without the owner to have a chance to remove the entry. This is because the dispose starts from the child. what the owner would know is the entry's notify the owner it has been disposed.

Things can be even worse if the entry is under another opaque entry and does not maintain state. In this case, owner won't even know the entry is disposed because it was never built

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

never mind If i try really hard, i can still solve this problem

@@ -3596,6 +3605,9 @@ class NavigatorState extends State<Navigator> with TickerProviderStateMixin, Res
_updateHeroController(null);
focusNode.dispose();
for (final _RouteEntry entry in _history) {
// for (final OverlayEntry overlayEntry in entry.route.overlayEntries) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about this commented out code?

@chunhtai chunhtai marked this pull request as draft May 11, 2023 15:41
@flutter-dashboard
Copy link

This pull request has been changed to a draft. The currently pending flutter-gold status will not be able to resolve until a new commit is pushed or the change is marked ready for review again.

For more guidance, visit Writing a golden file test for package:flutter.

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@@ -401,7 +401,7 @@ void main() {
],
);
await tester.pumpWidget(Container());
expect(results, equals(<String>['A: dispose', 'b: dispose']));
expect(results, equals(<String>['b: dispose', 'A: dispose']));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is more correct as it disposed the top most route first.

@@ -4171,7 +4171,7 @@ class RouteAnnouncementSpy extends Route<void> {
final AnnouncementCallBack? onDidPopNext;

@override
List<OverlayEntry> get overlayEntries => <OverlayEntry>[
final List<OverlayEntry> overlayEntries = <OverlayEntry>[
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the original code will create a new entry every time that will mess up the insert/remove overlay entry logic. previously this is not an issue because we didn't attempt to remove overlay entry when disposing the navigator

@@ -214,7 +214,9 @@ class OverlayEntry implements Listenable {
/// This method should only be called by the object's owner.
void dispose() {
assert(!_disposedByOwner);
assert(_overlay == null, 'An OverlayEntry must first be removed from the Overlay before dispose is called.');
// In case the owner of this Overlay
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

never mind If i try really hard, i can still solve this problem

@chunhtai chunhtai marked this pull request as ready for review May 11, 2023 20:51
@chunhtai
Copy link
Contributor Author

Several things makes this pr difficult than I think.

Some systems like HeroController have been operated on disposed Route, and they were somehow able to do that because we didn't properly clean up the route

There are also some logic to make sure the Route's dispose needs to wait for its subtree is properly disposed. This because the subtree may be using something like route's animationcontroller.

Therefore a notifier is introduced in overlayentry to let owner to listen for subtree disposal, but the problem with such logic is that you can't dispose the overlayentry when the notifer notify about the subtree disposal because of the changenotifier doesn't allow calling dispose during listener call back. This was previous ok because the route dispose doesn't properly clean up the overlay entry. Thus, I added a microtask to make sure the listener callback is done before disposing the route.

This created another issue that if a navigator is disposed, it expects all route to dispose. Because some of the dispose was scheduled in a microtask, the navigator won't be able to dispose. Therefore, I added a new lifecycle state called disposing. Navigator will keep track of routes in this state and will force these routes to dispose if Navigator itself is about to be disposed. This is ok because we know the subtree of the route must have been disposed already and we can safely clean up the route at this point

@chunhtai chunhtai requested a review from goderbauer May 11, 2023 21:05
@chunhtai
Copy link
Contributor Author

a friendly bump

Copy link
Member

@goderbauer goderbauer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines 2825 to 2826
disposing, // The entry is waiting for its subtree to disposed first. It should
// be in stored in the _entryWaitingForSubTreeDisposal
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

subtree = widget subtree? Maybe a little clearer:

"The entry is waiting for its widget subtree to be disposed first. It is stored in _entryWaitingForSubTreeDisposal while awaiting that."

route.dispose();
}

void dispose() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe leave a comment here or on forcedDispose explaining the difference...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

e.g. "dispose" waits for all overlayEntries to be unmounted before disposing the route.

engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request May 19, 2023
auto-submit bot pushed a commit to flutter/packages that referenced this pull request May 19, 2023
flutter/flutter@5ae6438...077d644

2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2e6b1e6c3458 to a0ea4d2d9ea5 (1 revision) (flutter/flutter#127203)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from e9178e115f14 to 2e6b1e6c3458 (1 revision) (flutter/flutter#127196)
2023-05-19 felangelov@gmail.com fix(flutter_tools): `findBundleFile` w/multiple flavor dimensions (flutter/flutter#127133)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2e8875870f52 to e9178e115f14 (1 revision) (flutter/flutter#127188)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from c7a209cc40c1 to 2e8875870f52 (1 revision) (flutter/flutter#127185)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 5a57ff52f0f7 to c7a209cc40c1 (2 revisions) (flutter/flutter#127175)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from bfbd2e1dafb0 to 5a57ff52f0f7 (1 revision) (flutter/flutter#127172)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from e64084596182 to bfbd2e1dafb0 (2 revisions) (flutter/flutter#127167)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 6bc60c8a9877 to e64084596182 (2 revisions) (flutter/flutter#127163)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from bca11a423f9c to 6bc60c8a9877 (1 revision) (flutter/flutter#127162)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 9039c2dfb74c to bca11a423f9c (2 revisions) (flutter/flutter#127156)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 3c23ddae1d2a to 9039c2dfb74c (2 revisions) (flutter/flutter#127154)
2023-05-19 47866232+chunhtai@users.noreply.github.com Properly cleans up routes (flutter/flutter#126453)
2023-05-19 36861262+QuncCccccc@users.noreply.github.com Remove deprecated `primaryVariant` and `secondaryVariant` from `ColorScheme` (flutter/flutter#127124)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 17227c16ca58 to 3c23ddae1d2a (2 revisions) (flutter/flutter#127147)
2023-05-18 36861262+QuncCccccc@users.noreply.github.com Update `useMaterial3` api doc (flutter/flutter#127142)
2023-05-18 engine-flutter-autoroll@skia.org Roll Flutter Engine from c7c679d6d411 to 17227c16ca58 (1 revision) (flutter/flutter#127143)
2023-05-18 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2c77c8011d45 to c7c679d6d411 (1 revision) (flutter/flutter#127139)
2023-05-18 engine-flutter-autoroll@skia.org Roll Flutter Engine from 5fb3179a19c3 to 2c77c8011d45 (2 revisions) (flutter/flutter#127131)
2023-05-18 joshualitt@google.com Migrate benchmarks to package:web (flutter/flutter#126848)
2023-05-18 engine-flutter-autoroll@skia.org Roll Flutter Engine from 237c60185ace to 5fb3179a19c3 (3 revisions) (flutter/flutter#127126)
2023-05-18 53684884+mhbdev@users.noreply.github.com Fixing richMessage gesture recognizer in tooltip widget (flutter/flutter#126207)
2023-05-18 engine-flutter-autoroll@skia.org Roll Flutter Engine from 843ce0bba356 to 237c60185ace (2 revisions) (flutter/flutter#127122)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC dit@google.com,rmistry@google.com,stuartmorgan@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
CaseyHillers pushed a commit to CaseyHillers/flutter that referenced this pull request May 24, 2023
nploi pushed a commit to nploi/packages that referenced this pull request Jul 16, 2023
flutter/flutter@5ae6438...077d644

2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2e6b1e6c3458 to a0ea4d2d9ea5 (1 revision) (flutter/flutter#127203)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from e9178e115f14 to 2e6b1e6c3458 (1 revision) (flutter/flutter#127196)
2023-05-19 felangelov@gmail.com fix(flutter_tools): `findBundleFile` w/multiple flavor dimensions (flutter/flutter#127133)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2e8875870f52 to e9178e115f14 (1 revision) (flutter/flutter#127188)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from c7a209cc40c1 to 2e8875870f52 (1 revision) (flutter/flutter#127185)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 5a57ff52f0f7 to c7a209cc40c1 (2 revisions) (flutter/flutter#127175)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from bfbd2e1dafb0 to 5a57ff52f0f7 (1 revision) (flutter/flutter#127172)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from e64084596182 to bfbd2e1dafb0 (2 revisions) (flutter/flutter#127167)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 6bc60c8a9877 to e64084596182 (2 revisions) (flutter/flutter#127163)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from bca11a423f9c to 6bc60c8a9877 (1 revision) (flutter/flutter#127162)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 9039c2dfb74c to bca11a423f9c (2 revisions) (flutter/flutter#127156)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 3c23ddae1d2a to 9039c2dfb74c (2 revisions) (flutter/flutter#127154)
2023-05-19 47866232+chunhtai@users.noreply.github.com Properly cleans up routes (flutter/flutter#126453)
2023-05-19 36861262+QuncCccccc@users.noreply.github.com Remove deprecated `primaryVariant` and `secondaryVariant` from `ColorScheme` (flutter/flutter#127124)
2023-05-19 engine-flutter-autoroll@skia.org Roll Flutter Engine from 17227c16ca58 to 3c23ddae1d2a (2 revisions) (flutter/flutter#127147)
2023-05-18 36861262+QuncCccccc@users.noreply.github.com Update `useMaterial3` api doc (flutter/flutter#127142)
2023-05-18 engine-flutter-autoroll@skia.org Roll Flutter Engine from c7c679d6d411 to 17227c16ca58 (1 revision) (flutter/flutter#127143)
2023-05-18 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2c77c8011d45 to c7c679d6d411 (1 revision) (flutter/flutter#127139)
2023-05-18 engine-flutter-autoroll@skia.org Roll Flutter Engine from 5fb3179a19c3 to 2c77c8011d45 (2 revisions) (flutter/flutter#127131)
2023-05-18 joshualitt@google.com Migrate benchmarks to package:web (flutter/flutter#126848)
2023-05-18 engine-flutter-autoroll@skia.org Roll Flutter Engine from 237c60185ace to 5fb3179a19c3 (3 revisions) (flutter/flutter#127126)
2023-05-18 53684884+mhbdev@users.noreply.github.com Fixing richMessage gesture recognizer in tooltip widget (flutter/flutter#126207)
2023-05-18 engine-flutter-autoroll@skia.org Roll Flutter Engine from 843ce0bba356 to 237c60185ace (2 revisions) (flutter/flutter#127122)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages
Please CC dit@google.com,rmistry@google.com,stuartmorgan@google.com on the revert to ensure that a human
is aware of the problem.

To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://bugs.chromium.org/p/skia/issues/entry?template=Autoroller+Bug

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 16, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 17, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 17, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/packages that referenced this pull request Aug 17, 2023
@polina-c polina-c added the a: leak tracking Issues and PRs related to memory leaks detected by leak_tracker label Sep 21, 2023
@polina-c polina-c changed the title Properly cleans up routes Properly cleans up routes [prod-leak-fix] Aug 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
a: leak tracking Issues and PRs related to memory leaks detected by leak_tracker autosubmit Merge PR when tree becomes green via auto submit App f: material design flutter/packages/flutter/material repository. f: routes Navigator, Router, and related APIs. framework flutter/packages/flutter repository. See also f: labels.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fix non-disposed ValueNotifier<_OverlayEntryWidgetState?> memory leak
3 participants