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