1*d9e8da70SAndroid Build Coastguard Worker# Shark 2*d9e8da70SAndroid Build Coastguard Worker 3*d9e8da70SAndroid Build Coastguard Worker<!-- Made with http://patorjk.com/text-color-fader/ --> 4*d9e8da70SAndroid Build Coastguard Worker**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*d9e8da70SAndroid Build Coastguard Worker 6*d9e8da70SAndroid Build Coastguard Worker<p align="center"> 7*d9e8da70SAndroid Build Coastguard Worker<img src="../images/shark.png" /> 8*d9e8da70SAndroid Build Coastguard Worker</p> 9*d9e8da70SAndroid Build Coastguard Worker 10*d9e8da70SAndroid Build Coastguard WorkerShark 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*d9e8da70SAndroid Build Coastguard Worker 12*d9e8da70SAndroid Build Coastguard WorkerShark is released in layers: 13*d9e8da70SAndroid Build Coastguard Worker 14*d9e8da70SAndroid Build Coastguard Worker1. **Shark Hprof**: Read and write records in hprof files. 15*d9e8da70SAndroid Build Coastguard Worker2. **Shark Graph**: Navigate the heap object graph. 16*d9e8da70SAndroid Build Coastguard Worker3. **Shark**: Generate heap analysis reports. 17*d9e8da70SAndroid Build Coastguard Worker4. **Shark Android**: Android heuristics to generate tailored heap analysis reports. 18*d9e8da70SAndroid Build Coastguard Worker5. **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. 19*d9e8da70SAndroid Build Coastguard Worker6. **LeakCanary**: Builds on top. It automatically watches destroyed activities and fragments, triggers a heap dump, runs Shark Android and then displays the result. 20*d9e8da70SAndroid Build Coastguard Worker 21*d9e8da70SAndroid Build Coastguard WorkerA few more things: 22*d9e8da70SAndroid Build Coastguard Worker 23*d9e8da70SAndroid Build Coastguard Worker* Shark is built on top of Okio. Okio makes it easy to parse heap dumps efficiently. 24*d9e8da70SAndroid Build Coastguard Worker* 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*d9e8da70SAndroid Build Coastguard Worker* 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*d9e8da70SAndroid Build Coastguard Worker* Shark is heavily tested (80% test coverage). 27*d9e8da70SAndroid Build Coastguard Worker* Shark can run in both Java and Android VMs, with no other dependency than Okio and Kotlin. 28*d9e8da70SAndroid Build Coastguard Worker* Shark can analyze both Java and Android VM hprof files. 29*d9e8da70SAndroid Build Coastguard Worker* Shark can deobfuscate hprof records if it has access to obfuscation mapping file. 30*d9e8da70SAndroid Build Coastguard Worker 31*d9e8da70SAndroid Build Coastguard Worker## Shark CLI 32*d9e8da70SAndroid Build Coastguard Worker 33*d9e8da70SAndroid Build Coastguard WorkerThe 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*d9e8da70SAndroid Build Coastguard Worker 35*d9e8da70SAndroid Build Coastguard WorkerInstall it via [Homebrew](https://brew.sh/): 36*d9e8da70SAndroid Build Coastguard Worker 37*d9e8da70SAndroid Build Coastguard Worker```bash 38*d9e8da70SAndroid Build Coastguard Workerbrew install leakcanary-shark 39*d9e8da70SAndroid Build Coastguard Worker``` 40*d9e8da70SAndroid Build Coastguard Worker 41*d9e8da70SAndroid Build Coastguard WorkerYou can also download it [here](https://github.com/square/leakcanary/releases/download/v{{ leak_canary.release }}/shark-cli-{{ leak_canary.release }}.zip). 42*d9e8da70SAndroid Build Coastguard Worker 43*d9e8da70SAndroid Build Coastguard WorkerYou can then look for leaks in apps on any connected device, for example: 44*d9e8da70SAndroid Build Coastguard Worker 45*d9e8da70SAndroid Build Coastguard Worker``` 46*d9e8da70SAndroid Build Coastguard Worker$ shark-cli --device emulator-5554 --process com.example.app.debug analyze 47*d9e8da70SAndroid Build Coastguard Worker``` 48*d9e8da70SAndroid Build Coastguard Worker 49*d9e8da70SAndroid Build Coastguard Worker!!! info 50*d9e8da70SAndroid Build Coastguard Worker `shark-cli` works with all debuggable apps, even if they don't include the `leakcanary-android` dependency. 51*d9e8da70SAndroid Build Coastguard Worker 52*d9e8da70SAndroid Build Coastguard WorkerRun `shark-cli` to see usage instructions: 53*d9e8da70SAndroid Build Coastguard Worker 54*d9e8da70SAndroid Build Coastguard Worker``` 55*d9e8da70SAndroid Build Coastguard Worker$ shark-cli 56*d9e8da70SAndroid Build Coastguard Worker 57*d9e8da70SAndroid Build Coastguard WorkerUsage: shark-cli [OPTIONS] COMMAND [ARGS]... 58*d9e8da70SAndroid Build Coastguard Worker 59*d9e8da70SAndroid Build Coastguard Worker ^`. .=""=. 60*d9e8da70SAndroid Build Coastguard Worker ^_ \ \ / _ _ \ 61*d9e8da70SAndroid Build Coastguard Worker \ \ { \ | d b | 62*d9e8da70SAndroid Build Coastguard Worker { \ / `~~~--__ \ /\ / 63*d9e8da70SAndroid Build Coastguard Worker { \___----~~' `~~-_/'-=\/=-'\, 64*d9e8da70SAndroid Build Coastguard Worker \ /// a `~. \ \ 65*d9e8da70SAndroid Build Coastguard Worker / /~~~~-, ,__. , /// __,,,,) \ | 66*d9e8da70SAndroid Build Coastguard Worker \/ \/ `~~~; ,---~~-_`/ \ / \/ 67*d9e8da70SAndroid Build Coastguard Worker / / '. .' 68*d9e8da70SAndroid Build Coastguard Worker '._.' _|`~~`|_ 69*d9e8da70SAndroid Build Coastguard Worker /|\ /|\ 70*d9e8da70SAndroid Build Coastguard Worker 71*d9e8da70SAndroid Build Coastguard WorkerOptions: 72*d9e8da70SAndroid Build Coastguard Worker -p, --process TEXT Full or partial name of a process, e.g. 73*d9e8da70SAndroid Build Coastguard Worker "example" would match "com.example.app" 74*d9e8da70SAndroid Build Coastguard Worker -d, --device ID device/emulator id 75*d9e8da70SAndroid Build Coastguard Worker -m, --obfuscation-mapping PATH path to obfuscation mapping file 76*d9e8da70SAndroid Build Coastguard Worker --verbose / --no-verbose provide additional details as to what 77*d9e8da70SAndroid Build Coastguard Worker shark-cli is doing 78*d9e8da70SAndroid Build Coastguard Worker -h, --hprof FILE path to a .hprof file 79*d9e8da70SAndroid Build Coastguard Worker --help Show this message and exit 80*d9e8da70SAndroid Build Coastguard Worker 81*d9e8da70SAndroid Build Coastguard WorkerCommands: 82*d9e8da70SAndroid Build Coastguard Worker interactive Explore a heap dump. 83*d9e8da70SAndroid Build Coastguard Worker analyze Analyze a heap dump. 84*d9e8da70SAndroid Build Coastguard Worker dump-process Dump the heap and pull the hprof file. 85*d9e8da70SAndroid Build Coastguard Worker strip-hprof Replace all primitive arrays from the provided heap dump with 86*d9e8da70SAndroid Build Coastguard Worker arrays of zeroes and generate a new "-stripped.hprof" file. 87*d9e8da70SAndroid Build Coastguard Worker``` 88*d9e8da70SAndroid Build Coastguard Worker 89*d9e8da70SAndroid Build Coastguard Worker 90*d9e8da70SAndroid Build Coastguard Worker## Shark code examples 91*d9e8da70SAndroid Build Coastguard Worker 92*d9e8da70SAndroid Build Coastguard Worker### Reading records in a hprof file 93*d9e8da70SAndroid Build Coastguard Worker 94*d9e8da70SAndroid Build Coastguard Worker```groovy 95*d9e8da70SAndroid Build Coastguard Workerdependencies { 96*d9e8da70SAndroid Build Coastguard Worker implementation 'com.squareup.leakcanary:shark-hprof:$sharkVersion' 97*d9e8da70SAndroid Build Coastguard Worker} 98*d9e8da70SAndroid Build Coastguard Worker``` 99*d9e8da70SAndroid Build Coastguard Worker 100*d9e8da70SAndroid Build Coastguard Worker```kotlin 101*d9e8da70SAndroid Build Coastguard Worker// Prints all class and field names 102*d9e8da70SAndroid Build Coastguard WorkerHprof.open(heapDumpFile) 103*d9e8da70SAndroid Build Coastguard Worker .use { hprof -> 104*d9e8da70SAndroid Build Coastguard Worker hprof.reader.readHprofRecords( 105*d9e8da70SAndroid Build Coastguard Worker recordTypes = setOf(StringRecord::class), 106*d9e8da70SAndroid Build Coastguard Worker listener = OnHprofRecordListener { position, record -> 107*d9e8da70SAndroid Build Coastguard Worker println((record as StringRecord).string) 108*d9e8da70SAndroid Build Coastguard Worker }) 109*d9e8da70SAndroid Build Coastguard Worker } 110*d9e8da70SAndroid Build Coastguard Worker``` 111*d9e8da70SAndroid Build Coastguard Worker 112*d9e8da70SAndroid Build Coastguard Worker### Navigating the heap object graph 113*d9e8da70SAndroid Build Coastguard Worker 114*d9e8da70SAndroid Build Coastguard Worker```groovy 115*d9e8da70SAndroid Build Coastguard Workerdependencies { 116*d9e8da70SAndroid Build Coastguard Worker implementation 'com.squareup.leakcanary:shark-graph:$sharkVersion' 117*d9e8da70SAndroid Build Coastguard Worker} 118*d9e8da70SAndroid Build Coastguard Worker``` 119*d9e8da70SAndroid Build Coastguard Worker 120*d9e8da70SAndroid Build Coastguard Worker```kotlin 121*d9e8da70SAndroid Build Coastguard Worker// Prints all thread names 122*d9e8da70SAndroid Build Coastguard WorkerHprof.open(heapDumpFile) 123*d9e8da70SAndroid Build Coastguard Worker .use { hprof -> 124*d9e8da70SAndroid Build Coastguard Worker val heapGraph = HprofHeapGraph.indexHprof(hprof) 125*d9e8da70SAndroid Build Coastguard Worker val threadClass = heapGraph.findClassByName("java.lang.Thread")!! 126*d9e8da70SAndroid Build Coastguard Worker val threadNames: Sequence<String> = threadClass.instances.map { instance -> 127*d9e8da70SAndroid Build Coastguard Worker val nameField = instance["java.lang.Thread", "name"]!! 128*d9e8da70SAndroid Build Coastguard Worker nameField.value.readAsJavaString()!! 129*d9e8da70SAndroid Build Coastguard Worker } 130*d9e8da70SAndroid Build Coastguard Worker threadNames.forEach { println(it) } 131*d9e8da70SAndroid Build Coastguard Worker } 132*d9e8da70SAndroid Build Coastguard Worker``` 133*d9e8da70SAndroid Build Coastguard Worker 134*d9e8da70SAndroid Build Coastguard Worker### Generating a heap analysis report 135*d9e8da70SAndroid Build Coastguard Worker 136*d9e8da70SAndroid Build Coastguard Worker```groovy 137*d9e8da70SAndroid Build Coastguard Workerdependencies { 138*d9e8da70SAndroid Build Coastguard Worker implementation 'com.squareup.leakcanary:shark:$sharkVersion' 139*d9e8da70SAndroid Build Coastguard Worker} 140*d9e8da70SAndroid Build Coastguard Worker``` 141*d9e8da70SAndroid Build Coastguard Worker 142*d9e8da70SAndroid Build Coastguard Worker```kotlin 143*d9e8da70SAndroid Build Coastguard Worker// Marks any instance of com.example.ThingWithLifecycle with 144*d9e8da70SAndroid Build Coastguard Worker// ThingWithLifecycle.destroyed=true as leaking 145*d9e8da70SAndroid Build Coastguard Workerval leakingObjectFilter = object : LeakingObjectFilter { 146*d9e8da70SAndroid Build Coastguard Worker override fun isLeakingObject(heapObject: HeapObject): Boolean { 147*d9e8da70SAndroid Build Coastguard Worker return if (heapObject instanceOf "com.example.ThingWithLifecycle") { 148*d9e8da70SAndroid Build Coastguard Worker val instance = heapObject as HeapInstance 149*d9e8da70SAndroid Build Coastguard Worker val destroyedField = instance["com.example.ThingWithLifecycle", "destroyed"]!! 150*d9e8da70SAndroid Build Coastguard Worker destroyedField.value.asBoolean!! 151*d9e8da70SAndroid Build Coastguard Worker } else false 152*d9e8da70SAndroid Build Coastguard Worker } 153*d9e8da70SAndroid Build Coastguard Worker} 154*d9e8da70SAndroid Build Coastguard Worker 155*d9e8da70SAndroid Build Coastguard Workerval leakingObjectFinder = FilteringLeakingObjectFinder(listOf(leakingObjectFilter)) 156*d9e8da70SAndroid Build Coastguard Worker 157*d9e8da70SAndroid Build Coastguard Workerval heapAnalysis = Hprof.open(heapDumpFile) 158*d9e8da70SAndroid Build Coastguard Worker .use { hprof -> 159*d9e8da70SAndroid Build Coastguard Worker val heapGraph = HprofHeapGraph.indexHprof(hprof) 160*d9e8da70SAndroid Build Coastguard Worker val heapAnalyzer = HeapAnalyzer(AnalyzerProgressListener.NONE) 161*d9e8da70SAndroid Build Coastguard Worker heapAnalyzer.analyze( 162*d9e8da70SAndroid Build Coastguard Worker heapDumpFile = heapDumpFile, 163*d9e8da70SAndroid Build Coastguard Worker graph = heapGraph, 164*d9e8da70SAndroid Build Coastguard Worker leakingObjectFinder = leakingObjectFinder, 165*d9e8da70SAndroid Build Coastguard Worker ) 166*d9e8da70SAndroid Build Coastguard Worker } 167*d9e8da70SAndroid Build Coastguard Workerprintln(analysis) 168*d9e8da70SAndroid Build Coastguard Worker``` 169*d9e8da70SAndroid Build Coastguard Worker 170*d9e8da70SAndroid Build Coastguard Worker### Generating an Android heap analysis report 171*d9e8da70SAndroid Build Coastguard Worker 172*d9e8da70SAndroid Build Coastguard Worker```groovy 173*d9e8da70SAndroid Build Coastguard Workerdependencies { 174*d9e8da70SAndroid Build Coastguard Worker implementation 'com.squareup.leakcanary:shark-android:$sharkVersion' 175*d9e8da70SAndroid Build Coastguard Worker} 176*d9e8da70SAndroid Build Coastguard Worker``` 177*d9e8da70SAndroid Build Coastguard Worker 178*d9e8da70SAndroid Build Coastguard Worker 179*d9e8da70SAndroid Build Coastguard Worker```kotlin 180*d9e8da70SAndroid Build Coastguard Workerval heapAnalyzer = HeapAnalyzer(AnalyzerProgressListener.NONE) 181*d9e8da70SAndroid Build Coastguard Workerval analysis = heapAnalyzer.checkForLeaks( 182*d9e8da70SAndroid Build Coastguard Worker heapDumpFile = heapDumpFile, 183*d9e8da70SAndroid Build Coastguard Worker referenceMatchers = AndroidReferenceMatchers.appDefaults, 184*d9e8da70SAndroid Build Coastguard Worker objectInspectors = AndroidObjectInspectors.appDefaults 185*d9e8da70SAndroid Build Coastguard Worker) 186*d9e8da70SAndroid Build Coastguard Workerprintln(analysis) 187*d9e8da70SAndroid Build Coastguard Worker``` 188