Skip to content

Commit

Permalink
fixup example
Browse files Browse the repository at this point in the history
  • Loading branch information
pyricau committed Jan 9, 2024
1 parent 29d592e commit b3d1511
Showing 1 changed file with 35 additions and 25 deletions.
60 changes: 35 additions & 25 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,26 @@ These alpha releases mark the start of the work on LeakCanary 3. It's not stable

New APIs, not stable yet: the `shark-heap-growth` artifact contains APIs for writing test scenarios that detect repeated heap growth.

Here's how it's used with an Espresso test:

```kotlin
class MyEspressoTest {

@Test
fun greeter_says_hello_does_not_leak() {
// Runs in a loop until the heap stops growing or we reach max heap dumps.
val heapTraversal = HeapGrowthDetector.detectRepeatedHeapGrowth {
// Runs repeatedly until the heap stops growing or we reach maxHeapDumps.
onView(withId(R.id.name_field)).perform(typeText("Steve"))
onView(withId(R.id.greet_button)).perform(click())
onView(withText("Hello Steve!")).check(matches(isDisplayed()))
}

assertThat(heapTraversal.growingNodes).isEmpty()
}
}
```

Here's an example set up, this is all very manual for now.

Add the new dependency:
Expand All @@ -25,21 +45,22 @@ dependencies {
Create an implementation setup for Espresso in process UI tests:

```kotlin

import leakcanary.AndroidDebugHeapDumper
import shark.AndroidReferenceMatchers
import shark.AndroidReferenceReaderFactory
import shark.CloseableHeapGraph
import shark.DiffingHeapGrowthDetector
import shark.HeapGraphProvider
import shark.HeapTraversal
import shark.HprofHeapGraph.Companion.openHeapGraph
import shark.IgnoredReferenceMatcher
import shark.LiveHeapGrowthDetector
import shark.LoopingHeapGrowthDetector
import shark.MatchingGcRootProvider
import shark.ReferencePattern.InstanceFieldPattern
import java.io.File
import java.text.SimpleDateFormat
import java.util.Date
import java.util.EnumSet
import java.util.Locale

/**
Expand All @@ -49,10 +70,12 @@ import java.util.Locale
* then assert that the resulting [shark.HeapTraversalWithDiff.growingNodes] is empty.
*/
val HeapGrowthDetector by lazy {
val referenceMatchers = AndroidReferenceMatchers.appDefaults + HeapTraversal.ignoredReferences
val referenceMatchers = AndroidReferenceMatchers.appDefaults +
HeapTraversal.ignoredReferences +
// https://cs.android.com/android/_/android/platform/frameworks/base/+/6985fb39f07294fb979b14ba0ebabfd2fea06d34
IgnoredReferenceMatcher(InstanceFieldPattern("android.os.StrictMode", "sLastVmViolationTime"))

val dateFormat = SimpleDateFormat("yyyy-MM-dd_HH-mm-ss_SSS'-heap-growth.hprof'", Locale.US)
// Magical path that we automatically upload as artifacts of failed builds in CI.
val uploadedTracesDirectory = File("/sdcard/traces/")
uploadedTracesDirectory.mkdirs()
check(uploadedTracesDirectory.exists()) {
Expand All @@ -66,7 +89,13 @@ val HeapGrowthDetector by lazy {
check(heapDumpFile.exists()) {
"Expected file to exist after heap dump: ${heapDumpFile.absolutePath}"
}
heapDumpFile.openHeapGraph()
val realGraph = heapDumpFile.openHeapGraph()
object : CloseableHeapGraph by realGraph {
override fun close() {
realGraph.close()
heapDumpFile.delete()
}
}
}

LiveHeapGrowthDetector(
Expand All @@ -81,6 +110,7 @@ val HeapGrowthDetector by lazy {
)
)
}

```

Ensure your UI tests have enough heap by updating `src/androidTest/AndroidManifest.xml`:
Expand All @@ -96,26 +126,6 @@ Ensure your UI tests have enough heap by updating `src/androidTest/AndroidManife
</manifest>
```

Use it:

```kotlin
class MyEspressoTest {

@Test
fun greeter_says_hello_does_not_leak() {
// Runs in a loop until the heap stops growing or we reach max heap dumps.
val heapTraversal = HeapGrowthDetector.detectRepeatedHeapGrowth {
// Runs repeatedly until the heap stops growing or we reach maxHeapDumps.
onView(withId(R.id.name_field)).perform(typeText("Steve"))
onView(withId(R.id.greet_button)).perform(click())
onView(withText("Hello Steve!")).check(matches(isDisplayed()))
}

assertThat(heapTraversal.growingNodes).isEmpty()
}
}
```

### Reference readers

New APIs, not stable yet: `ReferenceReader` implementations aka expanders, are now public APIs. The names might change. These class define how LeakCanary traverses the graph, and allow for the creating of virtual references, as [introduced here](#improved-support-for-data-structure-internals). These new APIs make it possible to add support for more custom data structures, and they're also useful when working directly with the `shark` APIs (for example, these APIs were necessary to build the heap growth detection tooling mentioned above).
Expand Down

0 comments on commit b3d1511

Please sign in to comment.