Skip to content

[iOS] FlutterViewController Memory Leak #163841

@JackCostigan

Description

@JackCostigan

Steps to reproduce

I am adding flutter screens to an existing iOS app using the add-to-app process.
I am using a subclass of FlutterViewController, and have found that it doesn't get collected by ARC after the view controller is popped off the navigation stack, as expected.

This behaviour is also present in the multiple flutters add-to-app sample code here.

Steps to reproduce:

  1. Build and run the "multiple flutters iOS" project as described at the link above.
  2. Tap the "Next" button to push an instance of SingleFlutterViewController onto the navigation stack.
  3. Press the back button to pop the SingleFlutterViewController off the navigation stack.
  4. Use the "Debug Memory Graph" feature on Xcode, and search for SingleFlutterViewController.

Expected result:
The SingleFlutterViewController has been collected by ARC and is not present in the memory graph.

Actual result:
The SingleFlutterViewController is present in the memory graph, even after it has been removed from the navigation controller.

Also note that pushing and popping multiple instances of SingleFlutterViewController will result in multiple instances being kept in the memory graph.

See attached screenshot of the Xcode memory graph.

Image

Experimentally, I found that calling destroyContext() on the FlutterViewControllers engine instance will cause the FlutterViewController to be collected.

So reworking the sample code as below fixes the issue, however I don't think I should have to manually call destroyContext.

class SingleFlutterViewController: UIViewController, DataModelObserver {
  private var channel: FlutterMethodChannel?
  private let flutterViewController: FlutterViewController

  init(withEntrypoint entryPoint: String?) {
    let appDelegate: AppDelegate = UIApplication.shared.delegate as! AppDelegate
    let newEngine = appDelegate.engines.makeEngine(withEntrypoint: entryPoint, libraryURI: nil)
    GeneratedPluginRegistrant.register(with: newEngine)
    flutterViewController = FlutterViewController(engine: newEngine, nibName: nil, bundle: nil)
    super.init(nibName: nil, bundle: nil)
    DataModel.shared.addObserver(observer: self)
  }

  deinit {
    DataModel.shared.removeObserver(observer: self)
    flutterViewController.engine.destroyContext()
  }

  required init(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  func onCountUpdate(newCount: Int64) {
    if let channel = channel {
      channel.invokeMethod("setCount", arguments: newCount)
    }
  }

  override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(flutterViewController.view)
    flutterViewController.view.frame = view.bounds
    addChild(flutterViewController)
    flutterViewController.didMove(toParent: self)
    channel = FlutterMethodChannel(
        name: "multiple-flutters", binaryMessenger: flutterViewController.engine.binaryMessenger)
    channel!.invokeMethod("setCount", arguments: DataModel.shared.count)
    let navController = self.navigationController!
    channel!.setMethodCallHandler { (call: FlutterMethodCall, result: @escaping FlutterResult) in
      if call.method == "incrementCount" {
        DataModel.shared.count = DataModel.shared.count + 1
        result(nil)
      } else if call.method == "next" {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let vc = storyboard.instantiateViewController(withIdentifier: "NativeViewCount")
        navController.pushViewController(vc, animated: true)
        result(nil)
      } else {
        result(FlutterMethodNotImplemented)
      }
    }
  }
}

Code sample

Code sample

As described above, see the add to app multiple flutters example.

What target platforms are you seeing this bug on?

iOS

OS/Browser name and version | Device information

I'm building using Xcode 16.2 and Mac OS 15.3.1.
I'm using Flutter 3.29.0.
I am running on an iPhone 16 Pro simulator, using iOS 18.3

Does the problem occur on emulator/simulator as well as on physical devices?

Unknown

Logs

Logs
[Paste your logs here]

Flutter Doctor output

Doctor output
[✓] Flutter (Channel stable, 3.29.0, on macOS 15.3.1 24D70 darwin-arm64 (Rosetta), locale en-GB) [895ms]
    • Flutter version 3.29.0 on channel stable at /Users/jackcostigan/development/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 35c388afb5 (11 days ago), 2025-02-10 12:48:41 -0800
    • Engine revision f73bfc4522
    • Dart version 3.7.0
    • DevTools version 2.42.2

[!] Android toolchain - develop for Android devices (Android SDK version 34.0.0) [933ms]
    • Android SDK at /Users/jackcostigan/Library/Android/sdk
    ✗ cmdline-tools component is missing
      Run `path/to/sdkmanager --install "cmdline-tools;latest"`
      See https://developer.android.com/studio/command-line for more details.
    ✗ Android license status unknown.
      Run `flutter doctor --android-licenses` to accept the SDK licenses.
      See https://flutter.dev/to/macos-android-setup for more details.

[✓] Xcode - develop for iOS and macOS (Xcode 16.2) [1,694ms]
    • Xcode at /Applications/Xcode-16.2.0.app/Contents/Developer
    • Build 16C5032a
    • CocoaPods version 1.16.2

[✗] Chrome - develop for the web (Cannot find Chrome executable at /Applications/Google Chrome.app/Contents/MacOS/Google
    Chrome) [47ms]
    ! Cannot find Chrome. Try setting CHROME_EXECUTABLE to a Chrome executable.

[✓] Android Studio (version 2023.1) [46ms]
    • 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
    • Java version OpenJDK Runtime Environment (build 17.0.7+0-17.0.7b1000.6-10550314)

[✓] VS Code (version 1.90.0) [42ms]
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension can be installed from:
      🔨 https://marketplace.visualstudio.com/items?itemName=Dart-Code.flutter

[✓] Connected device (3 available) [7.4s]
    • iPhone 16 Pro (mobile)          • C292E601-ED3D-4EFD-BC77-517D624BD6C7 • ios          • com.apple.CoreSimulator.SimRuntime.iOS-18-3
      (simulator)
    • macOS (desktop)                 • macos                                • darwin-arm64 • macOS 15.3.1 24D70 darwin-arm64 (Rosetta)
    • Mac Designed for iPad (desktop) • mac-designed-for-ipad                • darwin       • macOS 15.3.1 24D70 darwin-arm64 (Rosetta)

[✓] Network resources [913ms]
    • All expected network resources are available.

! Doctor found issues in 2 categories.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Important issues not at the top of the work lista: existing-appsIntegration with existing apps via the add-to-app flowcustomer: castawayengineflutter/engine related. See also e: labels.found in release: 3.29Found to occur in 3.29has reproducible stepsThe issue has been confirmed reproducible and is ready to work onperf: memoryPerformance issues related to memoryplatform-iosiOS applications specificallyteam-iosOwned by iOS platform teamtriaged-iosTriaged by iOS platform teamwaiting for customer responseThe Flutter team cannot make further progress on this issue until the original reporter responds

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions