Upgrade to Pro — share decks privately, control downloads, hide ads and more …

LeakCanary 2: Leaner, Better, Faster, Kotliner!

PY
April 22, 2019

LeakCanary 2: Leaner, Better, Faster, Kotliner!

LeakCanary 2 Alpha 1 will be released right before this talk, come learn about hot new features, crazy improvements and gnarly implementation details!

LeakCanary 1 helped detect memory leaks but had several issues: constant freeze of the UI, OOM crashes while analyzing, results hard to analyze, a confusing API, and an ugly logo.

No more! Come learn about multiple leak detection, leak grouping, smarter analysis results, counting leaks in production, detecting leaks in UI tests... and much more!

Oh and LeakCanary 2 is 100% Kotlin, updated to Android X, and it even has a cute new logo!

PY

April 22, 2019
Tweet

More Decks by PY

Other Decks in Programming

Transcript

  1. * Instance of com.squareup.ui.permissions.PasscodeUnlockView | mAccessibilityCursorPosition = -1 | mAccessibilityDelegate

    = null | mAccessibilityTraversalAfterId = -1 | mAccessibilityTraversalBeforeId = -1 | mAccessibilityViewId = -1 | mAnimator = null | mAttachInfo = null | mAttributes = null | mBackground = android.graphics.drawable.ColorDrawable@328049760 (0x138da | mBackgroundRenderNode = android.view.RenderNode@338685248 (0x142fed40) | mBackgroundResource = 0 | mBackgroundSizeChanged = false | mBackgroundTint = null | mBottom = 1731 | mCachingFailed = false | mClipBounds = null @Piwai
  2. class ActivityInspector : Reachability.Inspector { override fun expectedReachability(element: LeakTraceElement): Reachability

    { val fieldValue = element.getFieldReferenceValue("mDestroyed") if (fieldValue == null) { return Reachability.unknown() } return if (fieldValue == "true") { Reachability.unreachable("Activity#mDestroyed is true") } else { Reachability.reachable("Activity#mDestroyed is false") } } } @Piwai
  3. private fun createGroupHash(): String { val uniqueString = if (excludedLeak)

    { leakTrace.firstElementExclusion.matching } else { leakTrace.leakCauses .joinToString(separator = "") { element -> val referenceName = element.reference!!.groupingName element.className + referenceName } } return uniqueString.createSHA1Hash() } @Piwai
  4. fun open(heapDump: File): HprofParser { val inputStream = heapDump.inputStream() val

    channel = inputStream.channel val source = inputStream.source() .buffer() // ... } @Piwai
  5. fun open(heapDump: File): HprofParser { val inputStream = heapDump.inputStream() val

    channel = inputStream.channel val source = inputStream.source() .buffer() // ... } fun moveTo(newPosition: Long) { if (position == newPosition) { return } source.buffer.clear() channel.position(newPosition) position = newPosition } @Piwai
  6. while (!exhausted()) { // type of the record val tag

    = readUnsignedByte() // number of microseconds since the time stamp in the header skip(INT_SIZE) // number of bytes that follow and belong to this record val length = readUnsignedInt() when (tag) { STRING_IN_UTF8 -> { val callback = callbacks.get<StringRecord>() val id = readId() val stringLength = length - idSize val string = readUtf8(stringLength) callback(StringRecord(id, string)) } // ... @Piwai
  7. // ... LOAD_CLASS -> { val classSerialNumber = readInt() val

    id = readId() val stackTraceSerialNumber = readInt() val classNameStringId = readId() @Piwai