# Change Log Please thank our [contributors](https://github.com/square/leakcanary/graphs/contributors) ๐Ÿ™ ๐Ÿ™ ๐Ÿ™. I've started working on LeakCanary 3.0 so new 2.x releases only contain bug fixes and new known leak patterns. ## Version 2.13 (2024-01-01) * ๐Ÿ› [#2565](https://github.com/square/leakcanary/issues/2565) Fix AndroidX Fragments incorrectly marked as leaking if detached but not destroyed. * ๐Ÿ’ฅ [#2568](https://github.com/square/leakcanary/issues/2568) Fixed missing `RECEIVER_EXPORTED` flag when calling `registerReceiver()` on API 34+. * ๐Ÿ”จ [#2555](https://github.com/square/leakcanary/issues/2555) Binder stubs are now called out in leak traces. * ๐Ÿค [#2601](https://github.com/square/leakcanary/pull/2601) Added several known manufacturer & framework leaks. ## Version 2.12 (2023-06-29) * ๐Ÿ’ฅ [#2527](https://github.com/square/leakcanary/issues/2527) `LifecycleRegistry` in `androidx.lifecycle:lifecycle-runtime` was migrated to kotlin and its `mState` field name changed to `state` which broke LeakCanary expectations. * ๐Ÿค [#2545](https://github.com/square/leakcanary/pull/2545) Added several known manufacturer & framework leaks. ## Version 2.11 (2023-05-17) * ๐Ÿ› [#1764](https://github.com/square/leakcanary/issues/1764) Ignore phantom classes that were unloaded than reloaded (long time LeakCanary bug). * ๐Ÿ› [#2471](https://github.com/square/leakcanary/issues/2471) Fix LeakCanary introducing a weird leak in Google's CI infra. * ๐Ÿ› [#2496](https://github.com/square/leakcanary/issues/2496) Fix broken ViewModel leak detection ## Version 2.10 (2022-11-10) ### Experimental Neo4j heap dump exploration `shark-cli` has a new experiment `neo4j` command that will convert a heap dump into an embedded Neo4j database and then open Neo4j Browser to explore the heap dump. ``` brew install leakcanary-shark shark-cli --process com.example.app.debug neo4j ``` ![Neo4J heap dump](https://user-images.githubusercontent.com/557033/200693468-aa783bb4-9a5a-4a41-8b92-582d44b31b92.png) ### Other bug fixes and improvements ๐Ÿ›๐Ÿ”จ * ๐Ÿค [#2440](https://github.com/square/leakcanary/pull/2440) Add Android 13 `POST_NOTICICATIONS` permission as well as a new `LeakCanary.Config.showNotifications` config to disable notifications entirely. * ๐Ÿค [#2416](https://github.com/square/leakcanary/pull/2416) Add Android 13 monochrome icon. * ๐Ÿ’ฅ [#2371](https://github.com/square/leakcanary/issues/2371) Fix db crash when navigating heap dump screen. * ๐Ÿ› [#2393](https://github.com/square/leakcanary/issues/2393) Allow LeakCanary to be defined as an AndroidX Startup dependency. * ๐Ÿ’ฅ [#2430](https://github.com/square/leakcanary/issues/2430) Fix ShortcutManager crash on Android TV. * ๐Ÿ’ฅ [#2382](https://github.com/square/leakcanary/issues/2382) Fix heap dump close crash. This list reflects only a subset of all changes. For more details, see the [2.10 Milestone](https://github.com/square/leakcanary/milestone/25) and the [full diff](https://github.com/square/leakcanary/compare/v2.9.1...v2.10). ## Version 2.9.1 (2022-04-20) ### Preface What are some things you'd like to see in a future LeakCanary 3 version? Tell me [on Twitter](https://twitter.com/Piwai)! Some ideas I'm playing with: * Moving heap analysis leak visualisation to a separate single app (written with Compose!) available on the PlayStore. * Bumping Okio to 3.0 * Multiplatform heap analysis? Analyze a JVM heap dump in your browser?! * Visualize the heap dominators / retained size as a treemap. * A backend for LeakCanary? Anyway, that's still very much the future, let's talk about what's in `2.9.1` now! ### New metrics in heap analysis metadata I built LeakCanary to help fix leaks, but in doing so I accidentally wrote a fairly flexible heap dump parser. Since we're parsing the heap to find leaks anyway, we might as well report additional interesting metrics. Here's what you'll now see in the heap dump metadata: * Class count: count of loaded classes * Instance count * Primitive array count * Object array count * Thread count * Heap total bytes * Bitmap count * Bitmap total bytes * Large bitmap count (bitmaps with more pixels than 1.1x the pixels on screen) * Large bitmap total bytes * SQLiteDatabase in memory (open or closed, as well as their file path) This is just a first pass, feedback and ideas welcome! ### Performance improvements The heap analysis now traverses the heap dump using `RandomAccessFile` instead of `FileChannel.transferTo()` and is now 40% faster on API 23 and 20% faster on newer APIs. Also, sticky class GC roots are now deduplicated, which great reduces the memory footprint of LeakCanary on API 23 ([#2324](https://github.com/square/leakcanary/pull/2324)). You can read about the related investigation [on py.hashnode.dev](https://py.hashnode.dev/of-sharks-and-heaps-of-sticky-marshmallows). ### Breaking change: FailTestOnLeakRunListener deleted `FailTestOnLeakRunListener`, `FailTestOnLeak` and `FailAnnotatedTestOnLeakRunListener` were deprecated in LeakCanary 2.8 as they rely on hacking the Android Test library internals which have since changed, and have been replaced by `LeakAssertions.assertNoLeak()` and the `DetectLeaksAfterTestSuccess` test rule. I was initially planning of keep these around, but as I tried to increase API level coverage in LeakCanary I needed to upgrade the Android Test library to a more recent version, and the hacks now had compilation errors. So they're gone: [#2282](https://github.com/square/leakcanary/commit/7152d6e2f8bea866e3bd5397b882d5098bed7d8b). If you can't use the test rules just yet, you're welcome to copy paste the listener implementations in your own codebase. ### Other bug fixes and improvements ๐Ÿ›๐Ÿ”จ * ๐Ÿ’ฅ [#2367](https://github.com/square/leakcanary/pull/2367) Fixed `AndroidLeakFixes.FLUSH_HANDLER_THREADS` (`HandlerThread` can have a null `Looper`). * ๐Ÿ’ฅ [#2286](https://github.com/square/leakcanary/issues/2286) Update Curtains to include Proguard rules and prevent `WindowCallbackWrapper` crashes. * ๐Ÿ’ฅ [#2294](https://github.com/square/leakcanary/issues/2294) Fixed `WindowDelegateCallback.onMenuOpened()` crash. * ๐Ÿค [#2328](https://github.com/square/leakcanary/pull/2328) Fixed ToastEventListener leak. Sorry ๐Ÿ˜ฌ! * ๐Ÿ’ฅ [#2310](https://github.com/square/leakcanary/issues/2310) Fixed crash when using WorkManager < 2.1.0. * ๐Ÿ’ฅ [#2342](https://github.com/square/leakcanary/issues/2342) Fixed crash when `HashSet.map` is null (which isn't supposed to happen, oh well, Android ๐Ÿคทโ€โ™‚๏ธ). * ๐Ÿ› [#2117](https://github.com/square/leakcanary/issues/2117) Fixed StrictMode disk read violations. * ๐Ÿ’ฅ [#2351](https://github.com/square/leakcanary/pull/2351) Fixed a race causing a startup crash. * ๐Ÿ’ฅ [#2315](https://github.com/square/leakcanary/issues/2315) Fixed crash when using Okio 1.14. * ๐Ÿ› [#2182](https://github.com/square/leakcanary/issues/2182) Fixed multi rescheduling of `BackgroundListener$checkAppInBackground`. * ๐Ÿ’ฅ [#2360](https://github.com/square/leakcanary/issues/2360) Fixed SQLiteOpenHelper concurrent creation crash. This list reflects only a subset of all changes. For more details, see the [2.9 Milestone](https://github.com/square/leakcanary/milestone/23) and the [full diff](https://github.com/square/leakcanary/compare/v2.8.1...v2.9.1). ## Version 2.8.1 (2022-01-06) This is a bugfix release, a quick follow up to `2.8` which had a few major issues ๐Ÿ˜…. If you haven't yet, you should definitely read the `2.8` changelog. ### Thanks Please thank [@dicosta](https://github.com/dicosta), [@Goooler](https://github.com/Goooler), [@plnice](https://github.com/plnice), [@preetha1326](https://github.com/preetha1326) for their contributions, bug reports and feature requests ๐Ÿ™ ๐Ÿ™ ๐Ÿ™. ### Crash fixes ๐Ÿ’ฅ๐Ÿ’ฅ๐Ÿ’ฅ This patch release fixes not 1, not 2, but 3 crashes! * ๐Ÿ’ฅ [#2268](https://github.com/square/leakcanary/pull/2268) WorkManager expedited request crashes before API 31. * ๐Ÿ’ฅ [#2270](https://github.com/square/leakcanary/issues/2270) Updating `LeakCanary.config` crashes when `AppWatcher` is not installed. * ๐Ÿ’ฅ [#2271](https://github.com/square/leakcanary/issues/2271) Analysis failure on API 25 because `HashMap$Entry` became `HashMap$HashMapEntry` (on API 25) before it finally changed to `HashMap$Node`. For more details, see the [2.8.1 Milestone](https://github.com/square/leakcanary/milestone/24) and the [full diff](https://github.com/square/leakcanary/compare/v2.8...v2.8.1). ## Version 2.8 (2022-01-04) Note: please update to `2.8.1` instead. ### Preface The last release was 9 months ago. What happened?! Well, soon after releasing LeakCanary 2.7, I had my 2nd baby, a wonderful daughter ๐Ÿ˜. Having 2 young kids leaves a lot less time available for Open Source work... but it's worth it! โ€• [P.Y.](https://twitter.com/Piwai) ### Thanks Please thank [@aaronweihe](https://github.com/aaronweihe), [@alhah](https://github.com/alhah), [@Andre-max](https://github.com/Andre-max), [@AoraMD](https://github.com/AoraMD), [@BraisGabin](https://github.com/BraisGabin), [@breezenan](https://github.com/breezenan), [@Goooler](https://github.com/Goooler), [@iliaskomp](https://github.com/iliaskomp) [@Jeff11](https://github.com/Jeff11), [@jmnwong](https://github.com/jmnwong), [@IdioticMadman](https://github.com/IdioticMadman), [@keyur1sst](https://github.com/keyur1sst), [@lchen8](https://github.com/lchen8), [@leinardi](https://github.com/leinardi), [@Maragues](https://github.com/Maragues), [@mars885](https://github.com/mars885), [@mateuszkwiecinski](https://github.com/mateuszkwiecinski), [@matiash](https://github.com/matiash), [@maxxx](https://github.com/maxxx), [@preetha1326](https://github.com/preetha1326), [@SimonMarquis](https://github.com/SimonMarquis), [@slavonnet](https://github.com/slavonnet), [@Sonphil](https://github.com/Sonphil), [@summerlyr](https://github.com/summerlyr), [@SUPERCILEX](https://github.com/SUPERCILEX), [@utwyko](https://github.com/utwyko), [@ZacSweers](https://github.com/ZacSweers), [@ziranshang](https://github.com/ziranshang), [@zoltish](https://github.com/zoltish) for their contributions, bug reports and feature requests ๐Ÿ™ ๐Ÿ™ ๐Ÿ™. ### Improved support for data structure internals ๐Ÿค“ Inspired [by Android Studio](https://twitter.com/RalucaSauciuc/status/1343800565352996871), LeakCanary's node discovery during heap graph traversal is now abstracted away. This allows overlaying logical structure over common data structure internals. ๐Ÿ˜… WHAT?! ๐Ÿ‘‰ This means we can make known data structures look more like their APIs than their internals. For example, developers tend to think of setting a `HashMap` entry as `map["key"] = value` rather than `map.table[hash("key")].next.next.next = Node(value)`, which is what LeakCanary would previously show in its leak traces. Let's look at a `HashMap` example: ```kotlin class CheckoutController { val tabs = HashMap() fun addItemsTab(tab: Tab) { tabs["ItemsTab"] = tab } } ``` If the `Tab` instance holds on to a view, we might see a leak trace that would look like this: ``` โ”‚ ... โ”œโ”€ com.example.CheckoutController instance โ”‚ โ†“ CheckoutController.tabs โ”œโ”€ java.util.HashMap instance โ”‚ โ†“ HashMap.table โ”œโ”€ java.util.HashMap$Node[] array โ”‚ โ†“ HashMap$Node[42] โ”œโ”€ java.util.HashMap$Node instance โ”‚ โ†“ HashMap$Node.next โ”œโ”€ java.util.HashMap$Node instance โ”‚ โ†“ HashMap$Node.value โ”œโ”€ com.example.Tab instance โ”‚ ... ``` With the improved data structure support, the leak trace is much clearer (also note how the `ItemsTab` string key is now surfaced): ``` โ”‚ ... โ”œโ”€ com.example.CheckoutController instance โ”‚ โ†“ CheckoutController.tabs โ”œโ”€ java.util.HashMap instance โ”‚ โ†“ HashMap[ItemsTab] โ”œโ”€ com.example.Tab instance โ”‚ ... ``` Another benefit of this change is that leak signatures become less dependent of the runtime, and therefore are more consistent. This is especially true for any data structure that relies on a linked list (`HashMap`, `LinkedList`, `MessageQueue`, ...). Currently LeakCanary supports a limited set of common data structures from Apache Harmony, Open JDK, and the Android SDK. Let me know what else you need! ### ObjectAnimator leaks LeakCanary will now detect leaks that trigger when forgetting to cancel `ObjectAnimator`. This new feature is enabled by the node discovery changes described above! Let's say you accidentally start an infinite `ObjectAnimator` and never cancel it, like so: ```kotlin class ExampleActivity : Activity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) findViewById