Repository: flutter
Issue: [macOS] FlutterEngine caused Memory Leak after FlutterViewController was released
Labels: engine,platform-mac,a: existing-apps,a: desktop,perf: memory,has reproducible steps,P2,found in release: 2.10,found in release: 2.13,team-macos,triaged-macos

On macOS, after I create an extra FlutterViewController and release it, the memory allocated for the FlutterViewController is not totally released.

---

## Steps to Reproduce

1. Create a macOS demo
2. Copy and paste 'Code Sample' into MainFlutterWindow.swift 
3. flutter run --debug
4. The first window will be displayed after the Demo started, and the second window will show after 5 seconds.
5. Then we close the second window,  but the memory allocated for it is still exists. We think something wrong and caused the memory leak.

We can use Xcode Memeory Tools to observe the memory use:
![memory-1](https://user-images.githubusercontent.com/3714809/160752120-e29ac808-b7e2-436c-ba6b-d0184f12b343.png)

Then we use Xcode Memory Graph Tools to observe Flutter instance:
![memory-2](https://user-images.githubusercontent.com/3714809/160752194-fb7be618-103d-4f33-b85b-9bcd9174371b.png)

We can see that, although FlutterViewController has been released, but the FlutterEngine still exists. This proves that FlutterEngine case the memory leak.

**Expected results:** 
After releae the FlutterViewController, app memory usage should go back to the original level.

**Actual results:**
Something case memory leak.

<details>
<summary>Code sample</summary>

```dart
class MainFlutterWindow: NSWindow {
    override func awakeFromNib() {
        let flutterViewController = FlutterViewController.init()
        let windowFrame = self.frame
        self.contentViewController = flutterViewController
        self.setFrame(windowFrame, display: true)
        
        RegisterGeneratedPlugins(registry: flutterViewController)
        
        super.awakeFromNib()
        
        self.perform(#selector(showWindow2), with: nil, afterDelay: 5)
    }
    
    @objc func showWindow2() {
        
        let flutterViewController = FlutterViewController.init()
        var windowFrame = self.frame
        windowFrame.origin = CGPoint.init(x: windowFrame.origin.x + 50, y: windowFrame.origin.y + 50)
        
        let sub1Window = NSWindow(contentViewController: flutterViewController)
        sub1Window.contentViewController = flutterViewController
        sub1Window.setFrame(windowFrame, display: true)
        
        RegisterGeneratedPlugins(registry: flutterViewController)
        
        sub1Window.makeKeyAndOrderFront(nil)
    }
}
```

</details>

<details>
  <summary>Logs</summary>

```
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel stable, 2.10.3, on macOS 12.1 21C52 darwin-arm, locale zh-Hans-CN)
[!] Android toolchain - develop for Android devices (Android SDK version 32.1.0-rc1)
    ✗ 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/docs/get-started/install/macos#android-setup for more details.
[✓] Xcode - develop for iOS and macOS (Xcode 13.2.1)
[✓] Chrome - develop for the web
[✓] Android Studio (version 2021.1)
[✓] VS Code (version 1.65.2)
[✓] Connected device (2 available)
[✓] HTTP Host Availability

! Doctor found issues in 1 category.

```

</details>

---

## Diagnosis and Suggestion

After a series of debug and giagnosis，we thound we found the cause of th bug.

In the dealloc method of  FlutterViewController, FlutterEngine's setViewController method will be called:
![code-1](https://user-images.githubusercontent.com/3714809/160752432-6a723f10-45f5-44c1-864e-d6ab6fcef0eb.png)

![code-2](https://user-images.githubusercontent.com/3714809/160752485-7cbf9a0a-080e-4327-a885-0756dc7615e7.png)


By design, _flutterViewController should not be nil, and flutterViewController is nil, then shutDownEngine should be called. 
But acually, the FlutterViewController has into dealloc process, both _flutterViewController and flutterViewController is nil at this moment. So nothing FlutterEngine was leaked.

### Suggestion
FlutterEngine can provide a semantically explicit emthod for FlutterViewController to call when the controller enter dealloc method.