xref: /aosp_15_r20/external/leakcanary2/docs/shark.md (revision d9e8da70d8c9df9a41d7848ae506fb3115cae6e6)
1# Shark ��
2
3<!-- Made with http://patorjk.com/text-color-fader/ -->
4**Shark**: **<span style="color:#c757bc;">S</span><span style="color:#c858b7;">m</span><span style="color:#ca5ab2;">a</span><span style="color:#cb5bad;">r</span><span style="color:#cc5ca9;">t</span><span style="color:#ce5ea4;"> </span><span style="color:#cf5f9f;">H</span><span style="color:#d0609a;">e</span><span style="color:#d26295;">a</span><span style="color:#d36390;">p</span><span style="color:#d4658c;"> </span><span style="color:#d66687;">A</span><span style="color:#d76782;">n</span><span style="color:#d8697d;">a</span><span style="color:#da6a78;">l</span><span style="color:#db6b73;">y</span><span style="color:#dc6d6f;">s</span><span style="color:#de6e6a;">i</span><span style="color:#df6f65;">s</span><span style="color:#e07160;"> </span><span style="color:#e1725b;">R</span><span style="color:#e37356;">e</span><span style="color:#e47552;">p</span><span style="color:#e5764d;">o</span><span style="color:#e77748;">r</span><span style="color:#e87943;">t</span><span style="color:#e97a3e;">s</span><span style="color:#eb7b39;"> </span><span style="color:#ec7d35;">f</span><span style="color:#ed7e30;">o</span><span style="color:#ef802b;">r</span><span style="color:#f08126;"> </span><span style="color:#f18221;">K</span><span style="color:#f3841c;">o</span><span style="color:#f48518;">t</span><span style="color:#f58613;">l</span><span style="color:#f7880e;">i</span><span style="color:#f88909;">n</span>**
5
6<p align="center">
7<img src="../images/shark.png" />
8</p>
9
10Shark is the heap analyzer that powers LeakCanary 2. It's a Kotlin standalone heap analysis library that runs at **high speed** with a **low memory footprint**.
11
12Shark is released in layers:
13
141. **Shark Hprof**: Read and write records in hprof files.
152. **Shark Graph**: Navigate the heap object graph.
163. **Shark**: Generate heap analysis reports.
174. **Shark Android**: Android heuristics to generate tailored heap analysis reports.
185. **Shark CLI**: Analyze the heap of debuggable apps installed on an Android device connected to your desktop. The output is similar to the output of LeakCanary, except you don't have to add the LeakCanary dependency to your app.
196. **LeakCanary**: Builds on top. It automatically watches destroyed activities and fragments, triggers a heap dump, runs Shark Android and then displays the result.
20
21A few more things:
22
23* Shark is built on top of Okio. Okio makes it easy to parse heap dumps efficiently.
24* Shark is a 100% Kotlin library, and Kotlin is essential to its design, because Shark relies heavily on sealed classes and sequences to save memory.
25* Shark has the unique ability to help narrow down the cause of memory leaks through platform specific [heuristics](fundamentals-fixing-a-memory-leak.md#2-narrow-down-the-suspect-references).
26* Shark is heavily tested (80% test coverage).
27* Shark can run in both Java and Android VMs, with no other dependency than Okio and Kotlin.
28* Shark can analyze both Java and Android VM hprof files.
29* Shark can deobfuscate hprof records if it has access to obfuscation mapping file.
30
31## Shark CLI
32
33The Shark Command Line Interface (CLI) enables you to analyze heaps directly from your computer. It can dump the heap of an app installed on a connected Android device, analyze it, and even strip a heap dump of any sensitive data (e.g. PII, passwords or encryption keys) which is useful when sharing a heap dump.
34
35Install it via [Homebrew](https://brew.sh/):
36
37```bash
38brew install leakcanary-shark
39```
40
41You can also download it [here](https://github.com/square/leakcanary/releases/download/v{{ leak_canary.release }}/shark-cli-{{ leak_canary.release }}.zip).
42
43You can then look for leaks in apps on any connected device, for example:
44
45```
46$ shark-cli --device emulator-5554 --process com.example.app.debug analyze
47```
48
49!!! info
50    `shark-cli` works with all debuggable apps, even if they don't include the `leakcanary-android` dependency.
51
52Run `shark-cli` to see usage instructions:
53
54```
55$ shark-cli
56
57Usage: shark-cli [OPTIONS] COMMAND [ARGS]...
58
59                   ^`.                 .=""=.
60   ^_              \  \               / _  _ \
61   \ \             {   \             |  d  b  |
62   {  \           /     `~~~--__     \   /\   /
63   {   \___----~~'              `~~-_/'-=\/=-'\,
64    \                         /// a  `~.      \ \
65    / /~~~~-, ,__.    ,      ///  __,,,,)      \ |
66    \/      \/    `~~~;   ,---~~-_`/ \        / \/
67                     /   /            '.    .'
68                    '._.'             _|`~~`|_
69                                      /|\  /|\
70
71Options:
72  -p, --process TEXT              Full or partial name of a process, e.g.
73                                  "example" would match "com.example.app"
74  -d, --device ID                 device/emulator id
75  -m, --obfuscation-mapping PATH  path to obfuscation mapping file
76  --verbose / --no-verbose        provide additional details as to what
77                                  shark-cli is doing
78  -h, --hprof FILE                path to a .hprof file
79  --help                          Show this message and exit
80
81Commands:
82  interactive   Explore a heap dump.
83  analyze       Analyze a heap dump.
84  dump-process  Dump the heap and pull the hprof file.
85  strip-hprof   Replace all primitive arrays from the provided heap dump with
86                arrays of zeroes and generate a new "-stripped.hprof" file.
87```
88
89
90## Shark code examples
91
92### Reading records in a hprof file
93
94```groovy
95dependencies {
96  implementation 'com.squareup.leakcanary:shark-hprof:$sharkVersion'
97}
98```
99
100```kotlin
101// Prints all class and field names
102Hprof.open(heapDumpFile)
103    .use { hprof ->
104      hprof.reader.readHprofRecords(
105          recordTypes = setOf(StringRecord::class),
106          listener = OnHprofRecordListener { position, record ->
107            println((record as StringRecord).string)
108          })
109    }
110```
111
112### Navigating the heap object graph
113
114```groovy
115dependencies {
116  implementation 'com.squareup.leakcanary:shark-graph:$sharkVersion'
117}
118```
119
120```kotlin
121// Prints all thread names
122Hprof.open(heapDumpFile)
123    .use { hprof ->
124      val heapGraph = HprofHeapGraph.indexHprof(hprof)
125      val threadClass = heapGraph.findClassByName("java.lang.Thread")!!
126      val threadNames: Sequence<String> = threadClass.instances.map { instance ->
127        val nameField = instance["java.lang.Thread", "name"]!!
128        nameField.value.readAsJavaString()!!
129      }
130      threadNames.forEach { println(it) }
131    }
132```
133
134### Generating a heap analysis report
135
136```groovy
137dependencies {
138  implementation 'com.squareup.leakcanary:shark:$sharkVersion'
139}
140```
141
142```kotlin
143// Marks any instance of com.example.ThingWithLifecycle with
144// ThingWithLifecycle.destroyed=true as leaking
145val leakingObjectFilter = object : LeakingObjectFilter {
146  override fun isLeakingObject(heapObject: HeapObject): Boolean {
147    return if (heapObject instanceOf "com.example.ThingWithLifecycle") {
148      val instance = heapObject as HeapInstance
149      val destroyedField = instance["com.example.ThingWithLifecycle", "destroyed"]!!
150      destroyedField.value.asBoolean!!
151    } else false
152  }
153}
154
155val leakingObjectFinder = FilteringLeakingObjectFinder(listOf(leakingObjectFilter))
156
157val heapAnalysis = Hprof.open(heapDumpFile)
158    .use { hprof ->
159      val heapGraph = HprofHeapGraph.indexHprof(hprof)
160      val heapAnalyzer = HeapAnalyzer(AnalyzerProgressListener.NONE)
161      heapAnalyzer.analyze(
162          heapDumpFile = heapDumpFile,
163          graph = heapGraph,
164          leakingObjectFinder = leakingObjectFinder,
165      )
166    }
167println(analysis)
168```
169
170### Generating an Android heap analysis report
171
172```groovy
173dependencies {
174  implementation 'com.squareup.leakcanary:shark-android:$sharkVersion'
175}
176```
177
178
179```kotlin
180val heapAnalyzer = HeapAnalyzer(AnalyzerProgressListener.NONE)
181val analysis = heapAnalyzer.checkForLeaks(
182    heapDumpFile = heapDumpFile,
183    referenceMatchers = AndroidReferenceMatchers.appDefaults,
184    objectInspectors = AndroidObjectInspectors.appDefaults
185)
186println(analysis)
187```
188