!!! info To upgrade from LeakCanary 1.6, follow the upgrade guide.
Please thank @0x109, @andersu, @antoniomerlin, @bishiboosh, @ckesc, @jrodbx, @LouisCAD, @marcardar, @OlivierGenez, @pyricau, @runningcode, @seljad, @worldsnas for their contributions, bug reports and feature requests.
plumber-android
is a new artifact that fixes known Android leaks ๐ฝ๐งLeakCanary reports all leaks, including leaks caused by a known bug in 3rd party code that you do not have control over (reported as Library leaks). That can be annoying! LeakCanary now ships with a new dependency, plumber-android
, which performs hacks at runtime to fix some of these known leaks. This releases has fixes for 11 known leaks, but this is just the beginning. Contributions welcome! ๐
Note that since the leakcanary-android
dependency is usually added as a debugImplementation
dependency, the plumber-android
is transitively added only in debug builds, so it will not fix leaks in your release builds. You can add the dependency directly as implementation
to get these fixes in release builds as well:
dependencies { implementation 'com.squareup.leakcanary:plumber-android:2.4' }
!!! warning While several of these fixes already ship in release builds of Square apps, this is the first official release of plumber-android
, so you should consider it experimental.
The Shark CLI can now be installed via Homebrew
brew install leakcanary-shark
You can then look for leaks in apps on any connected device, for example:
$ shark-cli --device emulator-5554 --process com.example.app.debug analyze
If you set up LeakCanary to report test failures when detecting leaks in instrumentation tests, it now works with Android Test Orchestrator as well. No change required, LeakCanary will automatically detect thatAndroid Test Orchestrator is running and hook into it.
master
branchThe branch name master
comes from the master / slave terminology. We renamed the default branch to main
, a small step towards making the LeakCanary community a safer space. Here's a good thread on this topic.
This is a minor release on the feature front, but a large release on the documentation front!
Many thanks to @adamfit, @Amokrane, @Armaxis, @artnc, @burakeregar, @ClaasJG, @clementcontet, @ckesc, @cketti, @fbenbassat, @Guneetgstar, @Igorxp5, @JLLeitschuh, @KidAndroid, @ligi, @mzgreen, @pyricau, @sprintuu, @tevjef, @thrlr123 for the contributions, bug reports and feature requests.
We asked for help and immediately started seeing more contributions. Thanks all! Check out the How to help page.
Despite the documentation insisting on using debugImplementation
, we‘ve seen apps ship LeakCanary in release builds. Mistakes happen, so we’ve made that mistake harder to miss by making LeakCanary crash when included in release builds.
Learn More: LeakCanary in release builds.
The doc site content has changed quite a bit! We applied advice from Google's tech writing guide. If you've been confused by Library Leaks before, check out see the new Categorizing leaks section. Take a look around, let us know what you think.
For more details, see the 2.3 Milestone and the full diff.
We've got some good stuff for the first release of the decade!
Many thanks to @AndroidInternal, @Armaxis, @lic2050, @mzgreen, @orenktaboola, @personshelldon, @Plastix, @pyricau for the contributions, bug reports and feature requests.
Android ViewModels are really cool! Their lifecycle is much nicer than fragments or activities, but sometimes mistakes happen. LeakCanary will now automatically detect ViewModel leaks and report any ViewModel instance retained after its onCleared()
method was called.
LeakCanary is finally coming to big screens near you! Best part - no additional setup is required, just enable it like you would for a mobile device. Now whenever there's a leak - you will see a helpful Toast appear with all the details. Make sure to check out our new Android TV section and chill!
It was brought to our attention that configuring LeakCanary
and AppWatcher
was a miserable experience from Java code. Well, not anymore!
Now you can use LeakCanary.Config.Builder
and AppWatcher.Config.Builder
to have idiomatic Java when updating the configurations. For example:
LeakCanary.Config config = LeakCanary.getConfig().newBuilder() .retainedVisibleThreshold(3) .computeRetainedHeapSize(false) .build(); LeakCanary.setConfig(config);
If you notice any other problems when using LeakCanary from Java, please file an issue! We take Java-interop seriously and will be happy to improve LeakCanary's API!
For more details, see the 2.2 Milestone and the full diff.
A special New Year's Eve release ๐ฅณ, the next release will be in another decade ๐!
Many thanks to @adamfit, @alexander-smityuk, @Armaxis, @BraisGabin, @devism, @ditclear, @jrodbx, @jstefanowski, @Maragues, @mzgreen, @pyricau for the contributions, bug reports and feature requests.
It's fairly common for teams to have a QA build that is tested before making the release build. Usually that build will be obfuscated (via Proguard or R8), but also add LeakCanary to detect leaks during QA. This leads to obfuscated leak traces, which are hard to understand ๐คฏ. Check out our new Gradle deobfuscation plugin and rejoice!
In 2.0 we changed the LeakCanary UI and UX, and built a foundation on which 2.1 extends.
New
tag that will show until you open up a leak. There’s also a Library Leak
tag for leaks that are known to be caused by a bug in the Android Framework or Google libraries, and the library leak description now shows up in the UI.FontsContract class
and ExampleApplication instance
above.View
instances is now displayed in the leak trace. You shouldn't look at the implementation.โโ android.widget.TextView instance โ View.mID = R.id.helper_text
Leak
and LeakTrace
classes have significantly changed, e.g. all LeakTrace
instances with an identical signature are grouped under the same Leak object. Despite these breaking changes, this release version is a minor update. Oh noes, what about semantic versioning ๐ฑ? Ask Don Quixote.LeakCanary.config = LeakCanary.config.copy( leakingObjectFinder = FilteringLeakingObjectFinder( AndroidObjectInspectors.appLeakingObjectFilters ) )
org.junit.Test
is in the classpath. Unfortunately, some apps ship Junit in their app debug classpath (e.g. when using OkHttp MockWebServer). You can now customize which class is used to detect tests:<resources> <string name="leak_canary_test_class_name">assertk.Assert</string> </resources>
Shark CLI was rewritten on top of Clikt:
$ shark-cli Usage: shark-cli [OPTIONS] COMMAND [ARGS]... ^`. .=""=. ^_ \ \ / _ _ \ \ \ { \ | d b | { \ / `~~~--__ \ /\ / { \___----~~' `~~-_/'-=\/=-'\, \ /// a `~. \ \ / /~~~~-, ,__. , /// __,,,,) \ | \/ \/ `~~~; ,---~~-_`/ \ / \/ / / '. .' '._.' _|`~~`|_ /|\ /|\ Options: -p, --process NAME Full or partial name of a process, e.g. "example" would match "com.example.app" -d, --device ID device/emulator id -m, --obfuscation-mapping PATH path to obfuscation mapping file --verbose / --no-verbose provide additional details as to what shark-cli is doing -h, --hprof FILE path to a .hprof file --help Show this message and exit Commands: interactive Explore a heap dump. analyze Analyze a heap dump. dump-process Dump the heap and pull the hprof file. strip-hprof Replace all primitive arrays from the provided heap dump with arrays of zeroes and generate a new "-stripped.hprof" file.
There's a new interactive
command which enables exploring the heap dump from the command line:
$ shark-cli -h heapdump.hprof interactive Enter command [help]: help Available commands: analyze Analyze the heap dump. class NAME@ID Show class with a matching NAME and Object ID. instance CLASS_NAME@ID Show instance with a matching CLASS_NAME and Object ID. array CLASS_NAME@ID Show array instance with a matching CLASS_NAME and Object ID. ->instance CLASS_NAME@ID Show path from GC Roots to instance. ~>instance CLASS_NAME@ID Show path from GC Roots to instance, highlighting suspect references. help Show this message. exit Exit this interactive prompt.
We're currently exploring the idea of adding support for SQL queries, feedback welcome!
For more details, see the 2.1 Milestone and the full diff.
In the past 7 months, LeakCanary went through 3 alphas and 5 betas, encompassing 23 contributors over 493 commits, 35826 insertions and 10156 deletions.
YES! LeakCanary 2 is so much better, it might make you excited when you see a new memory leak. Follow the upgrade guide, you won't regret it!
Everything. The LeakCanary codebase went from ~6000 lines of Java to ~16000 lines of Kotlin, excluding comments & blanks.
!!! question “Isn't Kotlin supposed to drastically reduce the amount of boilerplate code?” Absolutely! And it did. But then, we wrote more code. LeakCanary used to depend on HAHA, a repackaging of perflib, the heap dump parser used by Android Studio. Unfortunately perflib was slow and used too much memory, so LeakCanary now includes its own heap dump parser: Shark. The extra code comes from Shark, but also from having a lot more automated tests, and an improved UI layer.
One major difference: when the app is in foreground, LeakCanary 2 will not trigger on every retained instance. Instead it will wait until the app goes in background or to reach a threashold of 5 retained instances in foreground. The analysis will then find all the leaks at once, and group identical leaks in the results UI. Please read the Fundamentals section to learn more!
Many thanks to @AndreasBoehm, @jrodbx, @pyricau for the contributions, bug reports and feature requests.
For more details, see the 2.0 Milestone and the full diff.
leak_canary_about_message
string triggered multiple substitutions warning) #1630Many thanks to @DanEdgarTarget, @msfjarvis, @PaulWoitaschek, @pyricau, @ZacSweers for the contributions, bug reports and feature requests.
For more details, see the 2.0-beta-5 Milestone and the full diff.
Many thanks to @Armaxis, @BraisGabin, @bric3, @elihart, @fernandospr, @flickator, @gabrysgab, @JorgeDLS, @lannyf77, @msfjarvis, @mzgreen, @ozmium, @PaulWoitaschek, @pyricau, @shelpy, @vRallev, @ZacSweers for the contributions, bug reports and feature requests.
For more details, see the 2.0-beta-4 Milestone and the full diff.
JavaLocalPattern
not matching on Lollipop #1524Many thanks to @Armaxis, @elihart, @emartynov, @hmcgreevy-instil, @pyricau for the contributions, bug reports and feature requests.
For more details, see the 2.0-beta-3 Milestone and the full diff.
Many thanks to @kolphi, @pyricau, @ZacSweers for the contributions, bug reports and feature requests.
For more details, see the 2.0-beta-2 Milestone and the full diff.
shark-cli analyze-process com.example.myapp
from your computer.Many thanks to @arctouch-carlosottoboni, @jemaystermind, @kushagrakumar27, @pyricau, @snkashis for the contributions, bug reports and feature requests.
For more details, see the 2.0-beta-1 Milestone and the full diff.
RefWatcher.retainedInstances
which returns the instances that are currently considered retained.LeakCanary.Config.maxStoredHeapDumps
(default 7) and LeakCanary.Config.requestWriteExternalStoragePermission
(default false). LeakCanary won't ask for the external storage permission anymore by default.LeakCanary.Config.exclusionsFactory
replaced with LeakCanary.Config.knownReferences
(simpler use), LeakCanary.Config.leakInspectors
and LeakCanary.Config.labelers
merged into LeakCanary.Config.leakTraceInspectors
which provides access to the entire leak trace as well as a new graph oriented API that replaces the low level hprof parser API.RefWatcher.hasRetainedReferences
=> RefWatcher.hasRetainedInstances
, RefWatcher.retainedReferenceCount
=> RefWatcher.retainedInstanceCount
, RefWatcher.hasWatchedReferences
=> RefWatcher.hasWatchedInstances
, RefWatcher.removeKeysRetainedBeforeHeapDump
=> RefWatcher.removeInstancesRetainedBeforeHeapDump
, RefWatcher.clearWatchedReferences
=> RefWatcher.clearWatchedInstances
.Many thanks to @1step2hell, @afollestad, @ansman, @bjdodson, @BraisGabin, @EBfVince, @jaredsburrows, @pforhan, @pyricau, @tellypresence, @wiyarmir for the contributions, bug reports and feature requests.
For more details, see the 2.0-alpha-3 Milestone and the full diff.
Many thanks to @forrestbice, @Foso, @Goddchen, @marcosholgado, @orionlee, @pyricau, @satoshun, @ZacSweers for the contributions!
For more details, see the 2.0-alpha-2 Milestone and the full diff.
leakcanary-android-perflib
but will be removed after alpha.Many thanks to @BraisGabin, @colinmarsch, @jrodbx, @flickator, @JakeWharton, @pyricau, @WhatsEmo for the contributions!
For more details, see the 2.0-alpha-1 Milestone and the full diff.
LeakCanary.isInAnalyzerProcess
now correctly returns true in the analyzer process prior to any first leak (could be triggered by starting the leak result activity).Many thanks to @KMaragh, @pyricau, @SebRut for the code contributions!
For more details, see the 1.6.3 Milestone and the full diff.
Many thanks to @fractalwrench, @ZacSweers, @Goddchen, @igokoro, @IlyaGulya, @JakeWharton, @javmarina, @jokermonn, @jrodbx, @Parseus, @pyricau, @scottkennedy for the code contributions!
AbstractAnalysisResultService
should now override onHeapAnalyzed(@NonNull AnalyzedHeap analyzedHeap)
instead of onHeapAnalyzed(@NonNull HeapDump heapDump, @NonNull AnalysisResult result)
For more details, see the 1.6.2 Milestone and the full diff.
Many thanks to @AdityaAnand1, @alhah, @christxph, @csoon03, @daqi, @JakeWharton, @jankovd, @jrodbx, @kurtisnelson, @NightlyNexus, @pyricau, @SalvatoreT, @shmuelr, @tokou, @xueqiushi for the code contributions!
Note: we made a 1.6 release but quickly followed up with 1.6.1 due to #1058.
LeakCanary.installedRefWatcher()
AnalysisResult.leakTraceAsFakeException()
returns an exception that can be used to report and group leak traces to a tool like Bugsnag or Crashlytics.InstrumentationLeakDetector
and FailTestOnLeakRunListener
APIs for detecting leaks in instrumentation tests.Reachability.Inspector
and RefWatcherBuilder.stethoscopeClasses()
API to establish reachability and help identify leak causes.AndroidRefWatcherBuilder.watchActivities(false)
, watching fragments can be disabled with AndroidRefWatcherBuilder.watchFragments(false)
LeakCanary.setDisplayLeakActivityDirectoryProvider()
is deprecated and replaced with LeakCanary.setLeakDirectoryProvider()
RefWatcherBuilder.computeRetainedHeapSize()
API to enable the computing of the retained heap size (off by default).For more details, see the 1.6.1 Milestone and the full diff.
For more details, see the full diff.
For more details, see the full diff.
For more details, see the full diff.
LeakCanary.isInAnalyzerProcess()
to the no-op jarLeakCanary.refWatcher()
.For more details, see the full diff.
HeapAnalyzer.findTrackedReferences()
method for headless analysis when you have no context on what leaked.LeakCanary.isInAnalyzerProcess()
to the no-op jarLeakCanary.refWatcher()
which returns an AndroidRefWatcherBuilder
that extends RefWatcherBuilder
and lets you fully customize the RefWatcher
instance.LeakCanary.install(Application, Class)
and LeakCanary.androidWatcher(Context, HeapDump.Listener, ExcludedRefs)
.R.integer.leak_canary_max_stored_leaks
and R.integer.leak_canary_watch_delay_millis
, those can now be set via LeakCanary.refWatcher()
.LeakDirectoryProvider
API to centralize all file related responsibilities.RefWatcher
is now constructed with a WatchExecutor
which executes a Retryable
, instead of an Executor
that executes a Runnable
.HeapDumper.NO_DUMP
was renamed HeapDumper.RETRY_LATER
leak_canary_
instead of __leak_canary
#161Throwable
instead of an Exception
. Main goal is to catch and correctly report OOMs while parsing.ExcludedRefs
fields.ExcludedRef
entry can now be ignored entirely or “kept only if no other path”.ExcludedRef
and AndroidExcludedRefs
are customizable: #12 #73.minSdkVersion
from 9
to 8
: #57.LeakCanary.leakInfo()
: #49.leakcanary-android-no-op
is lighter, it does not depend on leakcanary-watcher
anymore, only 2 classes now: #74.__leak_canary_heap_dump_toast.xml
(e.g. you could make it an empty layout).android.permission.WRITE_EXTERNAL_STORAGE
to leakcanary-android
artifact.LeakCanary.androidWatcher()
parameter types have changed (+ExcludedRefs).LeakCanary.leakInfo()
parameter types have changed (+boolean)ExcludedRef
is now serializable and immutable, instances can be created using ExcludedRef.Builder
.ExcludedRef
is available in HeapDump
AndroidExcludedRefs
is an enum, you can now pick the leaks you want to ignore in AndroidExcludedRefs
by creating an EnumSet
and calling AndroidExcludedRefs.createBuilder()
.AndroidExcludedRefs.createAppDefaults()
& AndroidExcludedRefs.createAndroidDefaults()
return a ExcludedRef.Builder
.ExcludedRef
moved from leakcanary-analyzer
to leakcanary-watcher
Initial release.