MixinNetwork / MixinNetwork/flutter-plugins
[desktop_multi_window] Handle leak (~3/cycle) when a sub-window is repeatedly destroyed and recreated
Nobody has claimed this yet.
- Dominant language
- C
- Stars
- 512
- Forks
- 292
- Avg merge
- 15h 8m
- Merged PRs (30d)
- 7
Description
Summary
When a desktop_multi_window sub-window is destroyed (e.g. it receives WM_CLOSE, or dies for any reason) and then recreated, the host process leaks ~3 Windows handles per recreate cycle (linear). There is no public API to destroy a sub-window (only show()/hide()), and the engine resources are not fully reclaimed when the window closes.
Environment
- Flutter 3.44.1 (stable), Windows 10 x64
desktop_multi_window: 0.3.0
Observed (measured)
Windows handle count via GetProcessHandleCount, across forced-destroy + auto-recreate cycles (PostMessage WM_CLOSE to the sub-window HWND, wait for the host app to recreate it):
| cycles | handles | WorkingSet | GDI | USER |
|---|---|---|---|---|
| baseline | 674 | 114.7 MB | 25 | 39 |
| after 15 | 720 (+46, ~3/cycle linear) | 127.2 MB (+12.5) | 25 (0) | 40 (+1) |
- Recreation succeeds 15/15, process never crashes.
- Normal operation (window kept alive, no recreation) shows no leak — handles stable (675 → 672) over 80s. So the leak is strictly tied to the destroy→recreate transition.
Analysis (from the 0.3.0 Windows source)
WindowController(Dart) exposes onlyshow()/hide()— there is noclose()/destroy().- The main channel
mixin.one/desktop_multi_windowhandles onlycreateWindow/getWindowDefinition/getAllWindows. FlutterWindow::OnDestroy()setsflutter_controller_ = nullptr(destroying theFlutterViewController) and callsRemoveManagedFlutterWindowLater(id). The managedFlutterWindowis only erased later viaCleanupRemovedWindows(), which is invoked solely on the nextCreate().- Even with that cleanup running, ~3 handles/cycle are not reclaimed — suggesting
FlutterViewController/engine teardown on Windows does not fully release its thread/event handles.
Reproduction
WindowController.create(...)a sub-window.- Force-close it:
PostMessage(hwnd, WM_CLOSE, 0, 0)to the sub-window's top-level HWND. - Recreate via
WindowController.create(...). - Repeat. Watch
GetProcessHandleCount(process)climb ~3 per cycle.
Impact
- Typical apps: negligible — sub-windows rarely die, so they're rarely recreated.
- Apps that auto-recreate a sub-window for resilience (e.g. an always-on-top overlay that respawns if it disappears) can accumulate handles over time if the window dies repeatedly.
Suggestions
- Add an explicit
WindowController.close()(Dart) +closeWindownative handler that destroys the sub-window and immediately tears down itsFlutterViewControllerand erases it frommanaged_flutter_windows_, instead of deferring to the nextCreate(). - Investigate whether
FlutterViewControllerteardown itself leaks handles on Windows — if so, an upstreamflutter/flutterfollow-up may be warranted.
Happy to provide the full measurement harness (Win32 EnumWindows/GetProcessHandleCount/GetGuiResources) if useful.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with WindowController and the desktop_multi_window channel handlers for createWindow, then trace FlutterWindow::OnDestroy(), RemoveManagedFlutterWindowLater(), and CleanupRemovedWindows(). Reproduce repeated WM_CLOSE and recreation while measuring GetProcessHandleCount; done means destroyed sub-windows are fully reclaimed without linear handle growth, with coverage for the destroy-and-recreate path.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- dart
- Domain
- desktop, operating-systems
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100