May 25th, 2025
This is the fourth and final blog post in the
Flutter – Detecting memory leaks
series. If you haven’t done so yet, I warmly suggest that you start with the
.
On September 1st 2022, Polina Cherkasova made the first commit to her newly tasked Dart-lang project called
. This core Flutter team member was given the task of creating a tool that would help detect non-disposed and non-garbage-collected objects.
The plan for this tool is to be included in the Dart DevTools once completed, but at the time of writing this article, it still hasn't been officially released (My active versions:
Flutter 3.27.1
,
Dart 3.6.0
,
DevTools 2.40.2
). As the documentation is nearly non-existent, I had to scour through the source code to understand how it works and how somebody can use it.
The goal of this article is to teach you how you can use it.
Dart team’s idea behind this package is simple. The package helps to identify and diagnose memory leaks in Dart applications.
Key
fe
a
tur
es:
Reading the code, I’ve identified a handful of places where I’ve noticed Leak Tracker’s methods being called on non-self-disposing object creation. If Leak Tracker is instantiated, it will:
Flutter SDK code example - ImageInfo object creation tracking
Flutter SDK code example - TrainHoppingAnimation object creation tracking
Flutter SDK code example - TextSelectionOverlay object creation tracking
How can you use Dart Leak Tracker before the official release? The documentation for setup on the official GitHub repository is outdated and no longer works. By fixing a bug in Dart Leak Tracker (
wasn’t merged yet), piecing together a few code snippets from a 2-year-old Reddit post and a few GitHub issues, I’ve managed to make it work.
To use Dart Leak Tracker inside your Flutter application, you must first fix the bug in the Dart Leak Tracker code. Navigate to where your
dart-lang
package is installed on your machine and open the
pkgs/leak_tracker/lib/src/leak_tracking/_object_tracker.dart
file. You need to fix the filter that filters leaks that are garbage collected late.
LeakType.gcedLate: _objects.gcedLateLeaks
// .where((record) => _leakFilter.shouldReport(LeakType.notGCed, record)) fixed
.where((record) => _leakFilter.shouldReport(LeakType.gcedLate, record))
.map((record) => record.toLeakReport())
.toList(),
});
Next, if you are using my code from the previous blog post in the series, replace the
main.dart
file contents with the contents found
. If you are looking for leaks in your app, make sure to add the following to your
main.dart
file (skip the steps if you are using my code):
You need to import the required dependencies, and before the
runApp
is called, you need to instantiate the Leak Tracking package.
import 'package:flutter/foundation.dart';
import "package:leak_tracker/leak_tracker.dart";
void main() {
LeakTracking.start();
FlutterMemoryAllocations.instance.addListener((ObjectEvent event) {
LeakTracking.dispatchObjectEvent(event.toMap());
});
runApp(const MyApp());
}
You need to implement a mechanism that will collect the currently observed leaks and return them to you. In my demo app, I have modified the
TextButton
’s onPressed callback so that it also collects the leaks.
onPressed: () async {
Navigator.pushReplacement(context, MaterialPageRoute(builder: (context) => const HomePage()));
await Future.delayed(const Duration(milliseconds: 500)); // let the leak_tracker settle
Leaks leaks = await LeakTracking.collectLeaks();
print("Leaks collected");
},
Run the app, do things that usually produce memory leaks, and then try to collect them. The quickest way to observe what has been collected is to place a breakpoint and check what was assigned to the
leaks
variable.
Keep in mind that
leak_tracker
package has not yet released, and it is possible that it didn’t find the culprit for your leaks.
Why didn’t leak_tracker find your leaks?
Now comes the hard part. The only thing remaining is to produce and analyse your app's memory dump. Memory dump analysis is out of scope for this blog post series, but I will happily
with you.