Coming soon! See flutter/devtools#3951.
The text below is under construction.
This page describes how to auto-detect certain types of memory leaks in Dart and Flutter applications and tests. See other information on memory leaks here.
-
Add leak_tracker to
dependencies
inpubspec.yaml
. -
Before
runApp
invocation, enable leak tracking, and connect the Flutter memory allocation events:
import 'package:flutter/foundation.dart';
import 'package:leak_tracker/leak_tracker.dart';
...
enableLeakTracking();
MemoryAllocations.instance
.addListener((ObjectEvent event) => dispatchObjectEvent(event.toMap()));
runApp(...
- Run the application in debug mode and watch for a leak related warnings. If you see a warning, open the link to investigate the leaks.
TODO(polina-c): implement the link and add example of the warning.
Wrap your tests with withLeakTracking
to setup automated leak verification:
test('...', () async {
final leaks = await withLeakTracking(
() async {
...
},
);
expect(leaks, leakFree);
});
Leak tracker does not work for web platform.
The leak tracker will catch leaks only for instrumented objects (See concepts for details).
However, the good news is:
-
Most disposable Flutter Framework classes include instrumentation. If how your Flutter app manages widgets results in leaks, Flutter will catch them.
-
If a leak involves at least one instrumented object, the leak will be caught and all other objects, even non-instrumented, will stop leaking as well.
See the instrumentation guidance.
The leak tracker availability differs by build modes. See Dart build modes or Flutter build modes.
Dart development and Flutter debug
Leak tracking is fully available.
Flutter profile
Leak tracking is available, but MemoryAllocations that listens to Flutter instrumented objects, should be turned on if you want to track Flutter Framework objects.
Dart production and Flutter release
Leak tracking is disabled.
NOTE: If you are interested in enabling leak tracking for release mode, please, comment here.
If you want to catch leaks for objects outside of Flutter Framework (that are already instrumented), you need to instrument them.
For each tracked object the library should get two signals from your code:
(1) the object is created and (2) the object is not in use.
It is most convenient to give the first signal in the constructor
and the second signal in the dispose
method:
import 'package:leak_tracker/src/leak_tracker.dart';
class InstrumentedClass {
InstrumentedClass() {
dispatchObjectCreated(
library: library,
className: '$InstrumentedClass',
object: this,
);
}
static const library = 'package:my_package/lib/src/my_lib.dart';
void dispose() {
dispatchObjectDisposed(object: this);
}
}
To start leak tracking, invoke enableLeakTracking()
,
to stop: disableLeakTracking()
.
TODO(polina-c): note that Flutter Framework enables leak tracking by default, when it is the case.
There are two steps in leak collection: (1) get signal that leaks happened (leak summary) and (2) get details about the leaks.
By default, the leak tracker checks for leaks every second, and,
if there are some, outputs the
summary to console and sends it to DevTools. Then you can get
leak details either by
requesting them from DevTools or by invoking collectLeaks()
programmatically.
You can change the default behavior by passing customized
configuration
to enableLeakTracking()
:
- Disable regular leak checking and check the leaks by calling
checkLeaks()
. - Disable output to console or to DevTools.
- Listen to the leaks with custom handler.
See DevTools > Memory > Leaks
guidance on how to interact with leak tracker.
TODO: add link to DevTools documentation.
The Leak Tracker stores a small additional record for each tracked alive object and for each detected leak, that increases the memory footprint.
For the Gallery application
in profile mode on macos
the leak tracking increased memory footprint of the home page
by ~400 KB that is ~0.5% of
the total.
Leak tracking impacts CPU in two areas: