fix(ios): hold navigation views weakly in the view registry so they deallocate on teardown - #752
Open
rafmsou wants to merge 2 commits into
Open
fix(ios): hold navigation views weakly in the view registry so they deallocate on teardown#752rafmsou wants to merge 2 commits into
rafmsou wants to merge 2 commits into
Conversation
`GoogleMapsNavigationViewRegistry` stored views in a strong dictionary but a view removes itself from the registry only in its `deinit` (`unregisterView()`). The strong entry keeps the view's reference count above zero after Flutter tears down the platform view, so `deinit` never runs, the view is never unregistered, and its underlying `GMSMapView` is retained for the lifetime of the process. Flutter assigns a new view id per platform-view creation, so nothing overwrites the stale entry either — one view leaks per view creation. Hold views via a weak wrapper so a released view deallocates, which triggers `deinit` and prunes the (now-empty) entry. `unregisterView` also drops entries whose weak reference has already been reclaimed so stale keys can't accumulate. CarPlay handling is unchanged (it has an explicit unregister path and never depended on `deinit`). Measured on a physical device: physical footprint climbed ~85 MB -> ~595 MB over ~4.5 min of map open/close cycles before the change, and reclaims between cycles after it.
|
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. |
rafmsou
marked this pull request as ready for review
August 13, 2026 20:11
illuminati1911
requested changes
Aug 14, 2026
illuminati1911
left a comment
Contributor
There was a problem hiding this comment.
Thanks a lot for the contribution. Few changes and I think should be good to go.
Address review: move the weak wrapper to a generic WeakRef<T> in Utilities.swift instead of a file-local class, drop the explanatory comment, and rename the registry dictionary to viewRefs to match its contents.
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.
Summary
On iOS, every
GoogleMapsMapView/GoogleMapsNavigationViewis retained for the lifetime of the process, so repeatedly creating and disposing map/nav views grows memory without bound and eventually leads to jetsam/WatchdogTerminationon memory-constrained devices.GoogleMapsNavigationViewRegistrystored views in a strong dictionary:but a view removes itself from the registry only in its
deinit(unregisterView()). The strong entry keeps the view's reference count above zero after Flutter tears down the platform view, sodeinitnever runs,unregisterView()is never called, and the view (and its underlyingGMSMapView) leaks forever. Flutter assigns a newviewIdper platform-view creation, so nothing overwrites the stale entry either — one view leaks per view creation.This is a self-referential retain: the only code that removes a view from the registry runs in
deinit, which the registry's own strong reference prevents from ever running.Fix
Hold views through a small
WeakViewRefwrapper instead of strongly. A released view then deallocates,deinitruns, and the entry is pruned.unregisterViewalso removes entries whose weak reference has already been reclaimed, so stale keys can't accumulate. All read accessorscompactMapover live views.CarPlay handling is unchanged:
carPlayViewhas an explicitunregisterCarPlayView()call path (fromBaseCarSceneDelegate) and never depended ondeinit, so it was not affected by this leak.Reproduction / verification
GoogleMapsMapView, dismiss it, repeat.Measured on an iPhone 11 / iOS 26.5: physical footprint climbed ~85 MB → ~595 MB over ~4.5 min of open/close cycles with no reclamation (~88 MB/min) before the change; after the change it reclaims between cycles.
Present at least through 0.9.4 and 0.10.0 (identical registry code).