InstrumentationLeakDetector can be used to detect memory leaks in instrumentation
tests.
To use it, you need to:
- Install a custom RefWatcher that will not trigger heapdumps while the tests run.
- Add an instrumentation test listener (a
RunListener) that will invoke
#detectLeaks()
Installing the instrumentation RefWatcher
For
#detectLeaks() to work correctly, the
RefWatcher must keep track of
references but not trigger any heap dump until this
#detectLeaks() runs, otherwise an
analysis in progress might prevent this listener from performing its own analysis.
Create and install the
RefWatcher instance using
#instrumentationRefWatcher(Application) instead of
LeakCanary#install(Application) or
LeakCanary#refWatcher(Context).
public class InstrumentationExampleApplication extends ExampleApplication {
@Override protected void setupLeakCanary() {
InstrumentationLeakDetector.instrumentationRefWatcher(this)
.buildAndInstall();
}
}
Add an intrumentation test listener
LeakCanary provides
FailTestOnLeakRunListener, but you should feel free to implement
your own
RunListener and call
#detectLeaks() directly if you need a more custom
behavior (for instance running it only once per test suite, or reporting to a backend).
All you need to do is add the following to the defaultConfig of your build.gradle:
testInstrumentationRunnerArgument "listener", "com.squareup.leakcanary.FailTestOnLeakRunListener"
Then you can run your instrumentation tests via Gradle as usually, and they will fail when
a memory leak is detected:
./gradlew leakcanary-sample:connectedCheck
If instead you want to run UI tests via adb, add a listener execution argument to
your command line for running the UI tests:
-e listener com.squareup.leakcanary.FailTestOnLeakRunListener
. The full command line
should look something like this:
adb shell am instrument \\
-w com.android.foo/android.support.test.runner.AndroidJUnitRunner \\
-e listener com.squareup.leakcanary.FailTestOnLeakRunListener
Rationale
Instead of using the
FailTestOnLeakRunListener, one could simply enable LeakCanary in
instrumentation tests.
This approach would have two disadvantages:
- Heap dumps freeze the VM, and the leak analysis is IO and CPU heavy. This can slow down
the test and introduce flakiness
- The leak analysis is asynchronous by default, and happens in a separate process. This means
the tests could finish and the process die before the analysis is finished.
The approach taken here is to collect all references to watch as you run the test, but not
do any heap dump during the test. Then, at the end, if any of the watched objects is still in
memory we dump the heap and perform a blocking analysis. There is only one heap dump performed,
no matter the number of objects leaking, and then we iterate on the leaking references in the
heap dump and provide all result in a
InstrumentationLeakResults.