flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
165.77k stars 27.38k forks source link

Google map prevents the parent widge from being GCed, which causes memory leaks. #149787

Closed Elvis5566 closed 4 months ago

Elvis5566 commented 4 months ago

google_maps_flutter version: 2.3.0

Steps to reproduce

My sample app has two page: 1. Home 2. MapSample(consists of GoogleMap)

  1. profile the sample app.
  2. take a memory snapshot.
  3. navigate to MapSample widget.
  4. back to previous page.
  5. GC manually.
  6. take another memory snapshot.
  7. diff these two snapshots.

MapSample cannot be GCed.

Expected results

MapSample should be GCed.

Actual results

MapSample cannot be GCed. the retaining path:

Root Isolate package:google_maps_flutter_android/src/google_maps_flutter_android.dart/GoogleMapsFlutterAndroid dart:async/_AsyncBroadcastStreamController dart:async/_BroadcastSubscription dart:core/_Closure Closure Context dart:async/_ForwardingStreamSubscription dart:core/_Closure Closure Context Closure Context dart:async/_SyncBroadcastStreamController dart:async/_BroadcastSubscription dart:core/_Closure Closure Context google_maps_flutter/GoogleMapController google_maps_flutter/_GoogleMapState google_maps_flutter/GoogleMap dart:core/_Closure Closure Context package:google_map_memory_leak/map_sample.dart/MapSampleState package:google_map_memory_leak/map_sample.dart/MapSample

It seems that I can use WeakReference to work around this issue, but the same technique does work for my production app.

Code sample

Code sample ```dart class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State createState() => _MyHomePageState(); } class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: TextButton( onPressed: () { Navigator.of(context).push( MaterialPageRoute( builder: (context) => MapSample(), ), ); }, child: const Text('Show map'), ), ), ); } } class MapSample extends StatefulWidget { const MapSample({Key? key}) : super(key: key); @override State createState() => MapSampleState(); } class MapSampleState extends State { final Completer _controller = Completer(); @override void dispose() { super.dispose(); _controller.future.then((value) => value.dispose()); } @override Widget build(BuildContext context) { final weakController = WeakReference(_controller); return GoogleMap( mapType: MapType.hybrid, initialCameraPosition: _kGooglePlex, onMapCreated: (GoogleMapController controller) { _controller.complete(controller); // weakController.target?.complete(controller); // a workaround? }, ); } static const CameraPosition _kGooglePlex = CameraPosition( target: LatLng(37.42796133580664, -122.085749655962), zoom: 14.4746, ); } ```

Flutter Doctor output

Doctor output ```console [✓] Flutter (Channel stable, 3.7.12, on macOS 14.4.1 23E224 darwin-arm64, locale en-TW) • Flutter version 3.7.12 on channel stable at /Users/elvislee/fvm/versions/3.7.12 • Upstream repository https://github.com/flutter/flutter.git • Framework revision 4d9e56e694 (1 year, 2 months ago), 2023-04-17 21:47:46 -0400 • Engine revision 1a65d409c7 • Dart version 2.19.6 • DevTools version 2.20.1 [✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0) • Android SDK at /Users/elvislee/Library/Android/sdk • Platform android-34, build-tools 34.0.0 • Java binary at: /opt/homebrew/opt/openjdk@17/bin/java • Java version OpenJDK Runtime Environment Homebrew (build 17.0.11+0) • All Android licenses accepted. [✓] Xcode - develop for iOS and macOS (Xcode 15.3) • Xcode at /Applications/Xcode.app/Contents/Developer • Build 15E204a • CocoaPods version 1.15.2 [✓] Chrome - develop for the web • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome [!] Android Studio (version 2023.3) • Android Studio at /Applications/Android Studio.app/Contents • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart ✗ Unable to find bundled Java version. • Try updating or re-installing Android Studio. [✓] IntelliJ IDEA Ultimate Edition (version 2024.1.2) • IntelliJ at /Applications/IntelliJ IDEA.app • Flutter plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/9212-flutter • Dart plugin can be installed from: 🔨 https://plugins.jetbrains.com/plugin/6351-dart [✓] Connected device (4 available) • SM N960F (mobile) • 258b9c0c3d0c7ece • android-arm64 • Android 10 (API 29) • Elvis’s iPhone (mobile) • 00008020-00040C6A1AB8003A • ios • iOS 17.4.1 21E236 • macOS (desktop) • macos • darwin-arm64 • macOS 14.4.1 23E224 darwin-arm64 • Chrome (web) • chrome • web-javascript • Google Chrome 125.0.6422.142 [✓] HTTP Host Availability • All required HTTP hosts are available ! Doctor found issues in 1 category. ```
huycozy commented 4 months ago

I see there's an open issue addressing the case you described https://github.com/flutter/flutter/issues/129089. That issue is marked for iOS platform but looks like it also appears on Android as well, see https://github.com/flutter/flutter/issues/129089#issuecomment-1600021331.

Closing this issue in favor of that issue, so please follow up on it for further updates. You can leave there a comment about platform where you see the issue that would be helpful. Thank you!

github-actions[bot] commented 4 months ago

This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.