Case study · Author & speaker
Leak Hunter demo (FlutterCon Europe 2025)
The open-source demo app and slides behind my FlutterCon Europe talk on advanced memory management in Flutter.
- Flutter
- Dart
- DevTools
Leak Hunter is the open-source Flutter app I built for my FlutterCon Europe 2025 talk, This App is Built Different: Advanced Memory Management in Flutter. It breaks on purpose: every screen reproduces one memory or performance problem, so it can be measured in Flutter DevTools, explained and fixed live on stage.
Problem
Memory problems in Flutter are easy to talk about and hard to show. Slides can explain garbage collection, but an audience only believes it when they watch the memory chart climb, press the GC button and see that nothing comes back. I needed an app where each problem is isolated, reproducible on demand and reversible, so I could switch between the broken and the fixed version in seconds during a talk.
What the app demonstrates
- Leaks. A screen that keeps memory reachable after it is closed: a periodic
Timerthat allocates a 5 MBUint8Listevery second into astaticlist, plus a sensor stream subscription (sensors_plus) that is never cancelled. Both are classic GC roots, so the garbage collector can't free anything they point to. - Bloat. Memory that is not leaked but is still far too large: big Dart buffers, decoded
ui.Imageobjects and native memory allocated throughdart:ffiwithmalloc, which the Dart garbage collector never sees and must be freed by hand. - Isolates. A deliberately heavy computation (matrix multiplication and prime counting) run once on the main isolate, where it freezes the UI, and once through
compute(), where the UI stays responsive. - Rebuilds. A "jank" mode with excessive rebuilds and CPU work next to an optimized mode, to compare red and green frames in the DevTools Performance view.
Architecture
Even a demo app gets read by other developers after a talk, so I structured it like a production codebase: clean architecture with MVVM and Riverpod.
- Domain: plain Dart entities (for example the memory-leak state) and repository interfaces, with no Flutter dependencies.
- Data: services that own the side effects (timers, sensors, buffer and native allocation, heavy computation) and repository implementations on top of them.
- Presentation: Riverpod
StateNotifierview models and pages that only render state and forward user actions.
Each demo is a feature folder (leaks, bloat, isolates, rebuilds) with the same three layers, so adding a new scenario means following an existing pattern instead of inventing one. The repository includes an ARCHITECTURE.md that explains the layers and the data flow.
Technologies
Flutter and Dart, flutter_riverpod for state and dependency injection, sensors_plus for the stream-subscription leak, dart:ffi and the ffi package for native memory, leak_tracker for leak events, and Flutter DevTools (Memory and Performance views) to observe everything.
Engineering decisions
- One problem per screen. Mixing problems makes the memory chart impossible to read. Isolating them makes each cause and each fix obvious.
- Every leak has a matching fix. The repository disposes the timer and cancels the subscription in the fixed path, so the difference between leaking and not leaking is a few lines of code anyone can compare.
- Native memory is shown separately. FFI allocations are the case where "the GC will handle it" is simply false, which is worth seeing next to normal Dart allocations.
- Leak tracking turned on in the app.
leak_trackerstarts inmain.dart, so leaks are reported as events, not only seen in charts.
Slides and teaching material
The repository also contains the slides for the core idea of the talk: reachable versus unreachable objects. They walk from GC roots (static variables, the call stack, active timers and streams) to why a static cache or an uncancelled timer keeps memory alive, and how the fixed version lets the collector do its job.
What I learned
- Showing beats telling. A climbing memory chart explains garbage-collection roots faster than any diagram.
- Most real leaks are lifecycle bugs: something that should have been cancelled or disposed in
dispose()wasn't. - Architecture is part of the message. When the demo is clean, people can focus on the memory behaviour instead of untangling the code.
The full source is on GitHub: maherjaafar/ftcon-25. The talk recording is on the talk page.