(Reopen of #776 since it appears closed issues are not monitored)
ApplicationLeak(className=com.myapp.Activity, leakTrace=
โฌ
โโ android.app.assist.AssistStructure$SendChannel
โ Leaking: UNKNOWN
โ GC Root: Global variable in native code
โ โ AssistStructure$SendChannel.mAssistStructure
โ ~~~~~~~~~~~~~~~~
โโ android.app.assist.AssistStructure
โ Leaking: UNKNOWN
โ โ AssistStructure.mWindowNodes
โ ~~~~~~~~~~~~
โโ java.util.ArrayList
โ Leaking: UNKNOWN
โ โ ArrayList.elementData
โ ~~~~~~~~~~~
โโ java.lang.Object[]
โ Leaking: UNKNOWN
โ โ array Object[].[0]
โ ~~~
โโ android.app.assist.AssistStructure$WindowNode
โ Leaking: UNKNOWN
โ โ AssistStructure$WindowNode.mRoot
โ ~~~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[0]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[1]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[0]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[0]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[5]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mText
โ ~~~~~
โโ android.app.assist.AssistStructure$ViewNodeText
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNodeText.mText
โ ~~~~~
โโ android.text.SpannableStringBuilder
โ Leaking: UNKNOWN
โ โ SpannableStringBuilder.mSpans
โ ~~~~~~
โโ java.lang.Object[]
โ Leaking: UNKNOWN
โ โ array Object[].[0]
โ ~~~
โโ com.myapp.spans.ClickSpan
โ Leaking: UNKNOWN
โ โ ClickSpan.listener
โ ~~~~~~~~
โโ com.myapp.MyFragment
โ Leaking: YES (Fragment#mFragmentManager is null)
โ โ MyFragment.textBox
โโ com.myapp.views.MyTextView
โ Leaking: YES (MyFragment is leaking and View.mContext references a destroyed activity)
โ mContext instance of com.myapp.Activity with mDestroyed = true
โ View#mParent is set
โ View#mAttachInfo is null (view detached)
โ View.mWindowAttachCount = 1
โ โ MyTextView.mContext
โฐโ com.myapp.Activity
โ Leaking: YES (MyTextView is leaking and Activity#mDestroyed is true and ObjectWatcher was watching this)
โ key = 61f611e3-b757-4c34-9a4f-d5369ba35865
โ watchDurationMillis = 4924
โ retainedDurationMillis = -89
, retainedHeapByteSize=124)
This is on OnePlus 7 Pro (GM1913) running Android 9.
I've been using version 2.0-beta-5 which should include the fix for this, however I'm still having LeakCanary report the following:
Known leak pattern: instance field android.app.assist.AssistStructure$ViewNodeText#mText
Description: AssistStructure (google assistant / autofill) holds on to text spannables on the screen. TextView.ChangeWatcher and android.widget.Editor end up in spans and typically hold on to the view hierarchy
1347879 bytes retained
โฌ
โโ android.app.assist.AssistStructure$SendChannel
โ Leaking: UNKNOWN
โ GC Root: Global variable in native code
โ โ AssistStructure$SendChannel.mAssistStructure
โ ~~~~~~~~~~~~~~~~
โโ android.app.assist.AssistStructure
โ Leaking: UNKNOWN
โ โ AssistStructure.mWindowNodes
โ ~~~~~~~~~~~~
โโ java.util.ArrayList
โ Leaking: UNKNOWN
โ โ ArrayList.elementData
โ ~~~~~~~~~~~
โโ java.lang.Object[]
โ Leaking: UNKNOWN
โ โ array Object[].[0]
โ ~~~
โโ android.app.assist.AssistStructure$WindowNode
โ Leaking: UNKNOWN
โ โ AssistStructure$WindowNode.mRoot
โ ~~~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[0]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[0]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[1]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[0]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[0]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mChildren
โ ~~~~~~~~~
โโ android.app.assist.AssistStructure$ViewNode[]
โ Leaking: UNKNOWN
โ โ array AssistStructure$ViewNode[].[6]
โ ~~~
โโ android.app.assist.AssistStructure$ViewNode
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNode.mText
โ ~~~~~
โโ android.app.assist.AssistStructure$ViewNodeText
โ Leaking: UNKNOWN
โ โ AssistStructure$ViewNodeText.mText
โ ~~~~~
โโ android.text.SpannableStringBuilder
โ Leaking: UNKNOWN
โ โ SpannableStringBuilder.mSpans
โ ~~~~~~
โโ java.lang.Object[]
โ Leaking: UNKNOWN
โ โ array Object[].[0]
โ ~~~
โโ RedactedActivity$StyleableClickSpan
โ Leaking: UNKNOWN
โ โ RedactedActivity$StyleableClickSpan.onClick
โ ~~~~~~~
โโ RedactedTextViewExtensionsKt$sam$java_lang_Runnable$0
โ Leaking: UNKNOWN
โ Anonymous class implementing java.lang.Runnable
โ โ TextViewExtensionsKt$sam$java_lang_Runnable$0.function
โ ~~~~~~~~
โโ RedactedFragment$onViewCreated$3
โ Leaking: UNKNOWN
โ Anonymous subclass of kotlin.jvm.internal.Lambda
โ โ RedactedFragment$onViewCreated$3.this$0
โ ~~~~~~
โฐโ RedactedFragment
โ Leaking: YES (Fragment#mFragmentManager is null and ObjectWatcher was watching this)
โ key = f0834154-b892-4b6e-a0ba-3b624b675fba
โ watchDurationMillis = 5401
โ retainedDurationMillis = 389
METADATA
Build.VERSION.SDK_INT: 28
Build.MANUFACTURER: Google
LeakCanary version: 2.0-beta-5
App process name: redacted
Analysis duration: 24689 ms
This is on an API 28 emulator. Is there a reason why it's still being reported?
In the logs, you see:
Leaks coming from the Android Framework or Google libraries.
and in the trace you pasted, at the top:
Known leak pattern: instance field android.app.assist.AssistStructure$ViewNodeText#mText
Description: AssistStructure (google assistant / autofill) holds on to text spannables on the screen. TextView.ChangeWatcher and android.widget.Editor end up in spans and typically hold on to the view hierarchy
This is still being reported because leakcanary cannot fix leaks for you.
Ah, so AndroidReferenceMatchers fills in details for _known_ leaks. It doesn't ignore them when they happen. I think I misunderstood it's purpose! Thanks.
Yep! What made you think it would ignore them / what do you think we could do to clarify this confusion for others as well?
I suppose my thinking was that if it is a known platform memory leak then there is no use in reporting it, as the app will likely not be able to fix the issue. Although in hindsight it may be able to do something else to mitigate/avoid it, so still worth showing.
Looking at https://square.github.io/leakcanary/api/shark-android/shark/-android-reference-matchers/ it's clearer now, but I only found this after I posted my first comment. This page explains the difference between known and ignored (false positives?) leaks and I think that makes general sense. I think this is more a case of RTFM on my side.
That said, let's say I have a particular case where we can't avoid this leak and it happens each time we go through a specific flow in the app, which ends up being an annoyance during development. Is there a way to ignore it? Is this actually even a good idea?
You can add your own custom "library leak patterns", and those could possibly match your own code. However LeakCanary has to analyze the heap to know what each leak is about, so you'll pay the cost anyway, it's only a classification difference. You're better off actually fixing that leak ;) . Even android framework leaks can be fixed with enough imagination and hackery.
Most helpful comment
You can add your own custom "library leak patterns", and those could possibly match your own code. However LeakCanary has to analyze the heap to know what each leak is about, so you'll pay the cost anyway, it's only a classification difference. You're better off actually fixing that leak ;) . Even android framework leaks can be fixed with enough imagination and hackery.