1Once LeakCanary is installed, it automatically detects and report memory leaks, in 4 steps: 2 31. Detecting retained objects. 42. Dumping the heap. 53. Analyzing the heap. 64. Categorizing leaks. 7 8## 1. Detecting retained objects 9 10LeakCanary hooks into the Android lifecycle to automatically detect when activities and fragments are destroyed and should be garbage collected. These destroyed objects are passed to an `ObjectWatcher`, which holds [weak references](https://en.wikipedia.org/wiki/Weak_reference) to them. LeakCanary automatically detects leaks for the following objects: 11 12* destroyed `Activity` instances 13* destroyed `Fragment` instances 14* destroyed fragment `View` instances 15* cleared `ViewModel` instances 16 17You can watch any objects that is no longer needed, for example a detached view or a destroyed presenter: 18 19```kotlin 20AppWatcher.objectWatcher.watch(myDetachedView, "View was detached") 21``` 22 23If the weak reference held by `ObjectWatcher` isn't cleared after **waiting 5 seconds** and running garbage collection, the watched object is considered **retained**, and potentially leaking. LeakCanary logs this to Logcat: 24 25``` 26D LeakCanary: Watching instance of com.example.leakcanary.MainActivity 27 (Activity received Activity#onDestroy() callback) 28 29... 5 seconds later ... 30 31D LeakCanary: Scheduling check for retained objects because found new object 32 retained 33``` 34 35LeakCanary waits for the count of retained objects to reach a threshold before dumping the heap, and displays a notification with the latest count. 36 37 38**Figure 1.** LeakCanary found 4 retained objects. 39 40``` 41D LeakCanary: Rescheduling check for retained objects in 2000ms because found 42 only 4 retained objects (< 5 while app visible) 43``` 44 45!!! info 46 The default threshold is **5 retained objects** when the app is **visible**, and **1 retained object** when the app is **not visible**. If you see the retained objects notification and then put the app in background (for example by pressing the Home button), then the threshold changes from 5 to 1 and LeakCanary dumps the heap within 5 seconds. Tapping the notification forces LeakCanary to dump the heap immediately. 47 48## 2. Dumping the heap 49 50When the count of retained objects reaches a threshold, LeakCanary dumps the Java heap into a `.hprof` file (a **heap dump**) stored onto the Android file system (see [Where does LeakCanary store heap dumps?](faq.md#where-does-leakcanary-store-heap-dumps)). Dumping the heap freezes the app for a short amount of time, during which LeakCanary displays the following toast: 51 52 53**Figure 2.** LeakCanary shows a [toast](https://developer.android.com/guide/topics/ui/notifiers/toasts) while dumping the heap. 54 55## 3. Analyzing the heap 56 57LeakCanary parses the `.hprof` file using [Shark](shark.md) and locates the retained objects in that heap dump. 58 59 60**Figure 3.** LeakCanary finds retained objects in the heap dump. 61 62For each retained object, LeakCanary finds the path of references that prevents that retained object from being garbage collected: its **leak trace**. You will learn to analyze a leak trace in the next section: [Fixing a memory leak](fundamentals-fixing-a-memory-leak.md). 63 64 65**Figure 4.** LeakCanary computes the leak trace for each retained object. 66 67When the analysis is done, LeakCanary displays a **notification** with a summary, and also prints the result in **Logcat**. Notice below how the **4 retained objects** are grouped as **2 distinct leaks**. LeakCanary creates a **signature for each leak trace**, and groups together leaks that have the same signature, ie leaks that are caused by the same bug. 68 69 70**Figure 5.** The 4 leak traces turned into 2 distinct leak signatures. 71 72 73``` 74==================================== 75HEAP ANALYSIS RESULT 76==================================== 772 APPLICATION LEAKS 78 79Displaying only 1 leak trace out of 2 with the same signature 80Signature: ce9dee3a1feb859fd3b3a9ff51e3ddfd8efbc6 81┬─── 82│ GC Root: Local variable in native code 83│ 84... 85``` 86 87Tapping the notification starts an activity that provides more details. Come back to it again later by tapping the LeakCanary launcher icon: 88 89 90**Figure 6.** LeakCanary adds a launcher icon for each app it's installed in. 91 92Each row corresponds to a **group of leaks with the same signature**. LeakCanary marks a row as <span style="border-radius: 20px; background: #ffd24c; padding-left: 8px; padding-right: 8px; padding-top: 2px; padding-bottom: 2px; color: #141c1f;">New</span> the first time the app triggers a leak with that signature. 93 94 95**Figure 7.** The 4 leaks grouped into 2 rows, one for each distinct leak signature. 96 97Tap on a leak to open up a screen with the leak trace. You can toggle between retained objects and their leak trace via a drop down. 98 99 100**Figure 8.** A screen showing 3 leaks grouped by their common leak signature. 101 102The **leak signature** is the **hash of the concatenation of each <span style="color: #9976a8;">reference</span> suspected to cause the leak**, ie each reference **<span style="text-decoration: underline; text-decoration-color: red; text-decoration-style: wavy; color: #9976a8;">displayed with a red underline</span>**: 103 104 105**Figure 9.** A leak trace with 3 suspect references. 106 107These same suspicious references are underlined with `~~~` when the leak trace is shared as text: 108 109``` 110... 111│ 112├─ com.example.leakcanary.LeakingSingleton class 113│ Leaking: NO (a class is never leaking) 114│ ↓ static LeakingSingleton.leakedViews 115│ ~~~~~~~~~~~ 116├─ java.util.ArrayList instance 117│ Leaking: UNKNOWN 118│ ↓ ArrayList.elementData 119│ ~~~~~~~~~~~ 120├─ java.lang.Object[] array 121│ Leaking: UNKNOWN 122│ ↓ Object[].[0] 123│ ~~~ 124├─ android.widget.TextView instance 125│ Leaking: YES (View.mContext references a destroyed activity) 126... 127``` 128 129In the example above, the signature of the leak would be computed as: 130 131```kotlin 132val leakSignature = sha1Hash( 133 "com.example.leakcanary.LeakingSingleton.leakedView" + 134 "java.util.ArrayList.elementData" + 135 "java.lang.Object[].[x]" 136) 137println(leakSignature) 138// dbfa277d7e5624792e8b60bc950cd164190a11aa 139``` 140 141## 4. Categorizing leaks 142 143LeakCanary separates the leaks it finds in your app into two categories: **Application Leaks** and **Library Leaks**. A **Library Leak** is a leak caused by a known bug in 3rd party code that you do not have control over. This leak is impacting your application, but unfortunately fixing it may not be in your control so LeakCanary separates it out. 144 145The two categories are separated in the result printed in **Logcat**: 146 147``` 148==================================== 149HEAP ANALYSIS RESULT 150==================================== 1510 APPLICATION LEAKS 152 153==================================== 1541 LIBRARY LEAK 155 156... 157┬─── 158│ GC Root: Local variable in native code 159│ 160... 161``` 162 163LeakCanary marks a row as a <span style="border-radius: 20px; background: #4e462f; padding-left: 8px; padding-right: 8px; padding-top: 2px; padding-bottom: 2px; color: #ffcc32;">Library Leak</span> in its list of leaks: 164 165 166**Figure 10.** LeakCanary found a Library Leak. 167 168LeakCanary ships with a database of known leaks, which it recognizes by pattern matching on reference names. For example: 169 170``` 171Leak pattern: instance field android.app.Activity$1#this$0 172Description: Android Q added a new IRequestFinishCallback$Stub class [...] 173┬─── 174│ GC Root: Global variable in native code 175│ 176├─ android.app.Activity$1 instance 177│ Leaking: UNKNOWN 178│ Anonymous subclass of android.app.IRequestFinishCallback$Stub 179│ ↓ Activity$1.this$0 180│ ~~~~~~ 181╰→ com.example.MainActivity instance 182``` 183 184!!! quote "What did I do to cause this leak?" 185 Nothing wrong! You used an API the way it was intended but the implementation has a bug that is causing this leak. 186 187!!! quote "Is there anything I can do to prevent it?" 188 Maybe! Some Library Leaks can be fixed using reflection, others by exercising a code path that makes the leak go away. This type of fix tends to be hacky, so beware! Your best option might be to find the bug report or file one, and insist that the bug gets fixed. 189 190!!! quote "Since I can't do much about this leak, is there a way I can ask LeakCanary to ignore it?" 191 There's no way for LeakCanary to know whether a leak is a Library Leak prior to dumping the heap and analyzing it. If LeakCanary didn't show the result notification when a Library Leak is found then you'd start wondering what happened to the LeakCanary analysis after the dumping toast. 192 193You can see the full list of known leaks in the [AndroidReferenceMatchers](https://github.com/square/leakcanary/blob/main/shark-android/src/main/java/shark/AndroidReferenceMatchers.kt#L49) class. If you find an Android SDK leak that isn't recognized, please [report it](faq.md#can-a-leak-be-caused-by-the-android-sdk). You can also [customize the list of known Library Leaks](recipes.md#matching-known-library-leaks). 194 195What's next? Learn how to [fix a memory leak](fundamentals-fixing-a-memory-leak.md)! 196