Skip to content

Conversation

@gentlemanxzh
Copy link
Contributor

@gentlemanxzh gentlemanxzh commented Apr 1, 2025

This PR is #4281 follow-up,Fix map memory leak

List which issues are fixed by this PR. You must list at least one issue.
#129089
Fixes #115283
#92788

Pre-Review Checklist

  • I read the [Contributor Guide] and followed the process outlined there for submitting PRs.
  • I read the [Tree Hygiene] page, which explains my responsibilities.
  • I read and followed the [relevant style guides] and ran the auto-formatter. (Unlike the flutter/flutter repo, the flutter/packages repo does use dart format.)
  • I signed the [CLA].
  • The title of the PR starts with the name of the package surrounded by square brackets, e.g. [shared_preferences]
  • I [linked to at least one issue that this PR fixes] in the description above.
  • I updated pubspec.yaml with an appropriate new version according to the [pub versioning philosophy], or I have commented below to indicate which [version change exemption] this PR falls under[^1].
  • I updated CHANGELOG.md to add a description of the change, [following repository CHANGELOG style], or I have commented below to indicate which [CHANGELOG exemption] this PR falls under[^1].
  • I updated/added any relevant documentation (doc comments with ///).
  • I added new tests to check the change I am making, or I have commented below to indicate which [test exemption] this PR falls under[^1].
  • All existing and new tests are passing.

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

@google-cla
Copy link

google-cla bot commented Apr 1, 2025

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@stuartmorgan-g stuartmorgan-g self-requested a review April 1, 2025 19:43
@gentlemanxzh
Copy link
Contributor Author

Will this PR still be reviewed? @stuartmorgan-g

Copy link
Collaborator

@stuartmorgan-g stuartmorgan-g left a comment

Choose a reason for hiding this comment

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

Thanks for the contribution!

@@ -1,3 +1,9 @@
## 2.12.2

* Fixes memory leak by implementing mechanism for disposing stream subscriptions in `GoogleMapController`.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just this sentence is enough for the changelog; anyone interested in the level of detail in the following sentences can always look into the PR and/or issue.

@@ -1,3 +1,9 @@
## 2.12.2

* Fixes memory leak by implementing mechanism for disposing stream subscriptions in `GoogleMapController`.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Also, "by implementing mechanism for disposing" -> "by disposing".

///
/// This list keeps track of all event subscriptions created for the map,
/// including camera movements, marker interactions, and other map events.
/// These subscriptions are properly disposed when the controller is disposed.
Copy link
Collaborator

Choose a reason for hiding this comment

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

"are properly disposed" -> "should be disposed"

Nothing about the existence of the field guarantees that the disposal actually happens, so the comment on the field shouldn't assert it.

/// This method is used to track and manage all stream subscriptions
/// created for map events. The subscriptions are stored in
/// [_streamSubscriptionList] and will be properly disposed when the
/// controller is disposed.
Copy link
Collaborator

Choose a reason for hiding this comment

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

This second sentence should be removed, as it is asserting things outside of the control of this method.

In general, it is an anti-pattern for a comment in one part of the code to make assertions about other code, because the chances of someone changing code updating all assertions about that code anywhere else in the codebase are extremely low, making them highly prone to becoming outdated and misleading.

/// This list keeps track of all event subscriptions created for the map,
/// including camera movements, marker interactions, and other map events.
/// These subscriptions are properly disposed when the controller is disposed.
final List<StreamSubscription<dynamic>> _streamSubscriptionList =
Copy link
Collaborator

Choose a reason for hiding this comment

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

Generally variable names shouldn't include their types unless they communicate some important information. This can just be called _streamSubscriptions.

/// [_streamSubscriptionList] and will be properly disposed when the
/// controller is disposed.
void _addSubscription(StreamSubscription<dynamic> subscription) {
_streamSubscriptionList.add(subscription);
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's the purpose of having a wrapper method? _addSubscription doesn't seem any more readable than _streamSubscriptions.add.


/// Adds a stream subscription to the tracked list for testing purposes.
///
/// This method allows tests to add custom stream subscriptions to the
Copy link
Collaborator

Choose a reason for hiding this comment

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

Adding visibleForTesting methods should only be done if there is no way to test the functionality using public APIs, and it generally indicates that some part of the actual production flow is not being tested.

In this case, this method is being used to bypass testing of all of the changes in _connectStreams. The goal of this PR is not for there to be a method that tracks subscriptions for disposal, the goal is for all the subscriptions to be cleaned up. If all of the changes to _connectStreams were reverted (or more subtly, any one of them were missing), the tests would still pass even though the issues this PR is intended to fix would not actually be fixed.

Given that the unit tests control the GoogleMapsFlutterPlatform.instance that vends all of the subscriptions, it should be possible to test—using only public API—that the platform instance's streams are listened to after init, but none of them are after dispose, thus fully verifying the desired behavior.

Copy link
Contributor Author

@gentlemanxzh gentlemanxzh Apr 11, 2025

Choose a reason for hiding this comment

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

You make a good point. Based on your suggestion, I was wondering if we could test this by checking the return value of (GoogleMapsFlutterPlatform.instance as FakeGoogleMapsFlutterPlatform).mapEventStreamController.hasListener. When the map is initialized, the return value would be true, indicating that the platform instance's stream is being listened to after initialization. When the map is disposed of, the return value would be false, indicating that the stream is no longer being listened to.

final FakePlatformViewsController fakePlatformViewsController =
FakePlatformViewsController();

tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(
Copy link
Collaborator

Choose a reason for hiding this comment

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

What issue was this code added to solve? Tests at this layer should not be relying on the internal implementation details of a (legacy) implementation from another package. Since you're setting the fake instance above it's not clear to me what code could be triggering calls to this handler.

fakePlatformViewsController.fakePlatformViewsMethodHandler,
);

final ValueNotifier<GoogleMapController?> controllerNotifier =
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why is this a value notifier rather than completer? Nothing registers any listeners so it's not clear to me what this is doing.


controllerNotifier.dispose();
} else {
fail('GoogleMapController not created');
Copy link
Collaborator

Choose a reason for hiding this comment

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

This will fail racily, because nothing is waiting onMapCompleter. Using a completer with an await will fix that, and avoid the need to even have this code.

if (controller != null) {
expect(platform.mapEventStreamController.hasListener, true);

await tester.pumpWidget(const Directionality(
Copy link
Collaborator

Choose a reason for hiding this comment

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

An explicit comment that this is removing the map from the widget tree would help make it clear what is happening here; it's easy to miss while reading that this isn't the usual test boilerplate of putting the widget under test in the tree (and is in fact the opposite).

@stuartmorgan-g stuartmorgan-g changed the title Fix for memory leak impacting all platforms due to subscriptions not getting cleaned up [google_maps_flutter] Fix for memory leak impacting all platforms due to subscriptions not getting cleaned up Apr 23, 2025
Copy link
Collaborator

@stuartmorgan-g stuartmorgan-g left a comment

Choose a reason for hiding this comment

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

LGTM

@bparrishMines Could you do the secondary review here?

Copy link
Contributor

@bparrishMines bparrishMines left a comment

Choose a reason for hiding this comment

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

LGTM

@stuartmorgan-g stuartmorgan-g added the autosubmit Merge PR when tree becomes green via auto submit App label May 8, 2025
@auto-submit auto-submit bot merged commit ab44c26 into flutter:main May 8, 2025
82 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request May 8, 2025
github-merge-queue bot pushed a commit to flutter/flutter that referenced this pull request May 8, 2025
flutter/packages@b2ce3b0...ab44c26

2025-05-08 31216074+gentlemanxzh@users.noreply.github.com
[google_maps_flutter] Fix for memory leak impacting all platforms due to
subscriptions not getting cleaned up (flutter/packages#8972)
2025-05-08 engine-flutter-autoroll@skia.org Roll Flutter from
cfb887c to b0f5c8c (281 revisions) (flutter/packages#9223)
2025-05-08 10687576+bparrishMines@users.noreply.github.com
[interactive_media_ads] Fixes support for ad tag URLs that do not
contain a query (flutter/packages#9176)

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-flutter-autoroll
Please CC flutter-ecosystem@google.com on the revert to ensure that a
human
is aware of the problem.

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

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
basemosama added a commit to basemosama/packages that referenced this pull request Jun 1, 2025
…orms due to subscriptions not getting cleaned up (flutter#8972)"

This reverts commit ab44c26.
basemosama added a commit to basemosama/packages that referenced this pull request Jun 1, 2025
…orms due to subscriptions not getting cleaned up (flutter#8972)"

This reverts commit ab44c26.
androidseb pushed a commit to androidseb/packages that referenced this pull request Jun 8, 2025
… to subscriptions not getting cleaned up (flutter#8972)

This PR is flutter#4281 follow-up,Fix map memory leak

*List which issues are fixed by this PR. You must list at least one issue.*
[#129089](flutter/flutter#129089)
Fixes [#115283](flutter/flutter#115283)
[#92788](flutter/flutter#92788)

## Pre-Review Checklist
FMorschel pushed a commit to FMorschel/packages that referenced this pull request Jun 9, 2025
… to subscriptions not getting cleaned up (flutter#8972)

This PR is flutter#4281 follow-up,Fix map memory leak

*List which issues are fixed by this PR. You must list at least one issue.*
[#129089](flutter/flutter#129089)
Fixes [#115283](flutter/flutter#115283)
[#92788](flutter/flutter#92788)

## Pre-Review Checklist
Ortes pushed a commit to Ortes/packages that referenced this pull request Jun 25, 2025
… to subscriptions not getting cleaned up (flutter#8972)

This PR is flutter#4281 follow-up,Fix map memory leak

*List which issues are fixed by this PR. You must list at least one issue.*
[#129089](flutter/flutter#129089)
Fixes [#115283](flutter/flutter#115283)
[#92788](flutter/flutter#92788)

## Pre-Review Checklist
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App p: google_maps_flutter

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[google_maps_flutter] GoogleMapsFlutter plugin is executing callbacks after the widget is disposed

3 participants