无法在泄漏金丝雀跟踪中找到原因

Posted

技术标签:

【中文标题】无法在泄漏金丝雀跟踪中找到原因【英文标题】:Not able to find cause in Leak canary trace 【发布时间】:2020-06-22 15:33:17 【问题描述】:

Leak Canary 报告了我们的应用程序中的泄漏,并带有以下堆栈跟踪:

06-20 18:40:32.018916 13804 30781 D LeakCanary: HeapAnalysisSuccess(heapDumpFile=/data/user/0/<>./files/leakcanary/2020-06-20_18-11-16_713.hprof, createdAtTimeMillis=1592703632012, analysisDurationMillis=130036, applicationLeaks=[], libraryLeaks=[LibraryLeak(className=<>.MediaControlActivity, leakTrace=
06-20 18:40:32.018916 13804 30781 D LeakCanary: ┬
06-20 18:40:32.018916 13804 30781 D LeakCanary: ├─ android.os.MessageQueue
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    Leaking: NO (MessageQueue#mQuitting is false)
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    GC Root: Input or output parameters in native code
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    ↓ MessageQueue.mMessages
06-20 18:40:32.018916 13804 30781 D LeakCanary: │                   ~~~~~~~~~
06-20 18:40:32.018916 13804 30781 D LeakCanary: ├─ android.os.Message
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    Leaking: UNKNOWN
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    ↓ Message.next
06-20 18:40:32.018916 13804 30781 D LeakCanary: │              ~~~~
06-20 18:40:32.018916 13804 30781 D LeakCanary: ├─ android.os.Message
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    Leaking: UNKNOWN
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    ↓ Message.callback
06-20 18:40:32.018916 13804 30781 D LeakCanary: │              ~~~~~~~~
06-20 18:40:32.018916 13804 30781 D LeakCanary: ├─ android.view.ViewRootImpl$1
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    Leaking: UNKNOWN
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    Anonymous class implementing java.lang.Runnable
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    ↓ ViewRootImpl$1.this$0
06-20 18:40:32.018916 13804 30781 D LeakCanary: │                     ~~~~~~
06-20 18:40:32.018916 13804 30781 D LeakCanary: ├─ android.view.ViewRootImpl
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    Leaking: YES (ViewRootImpl#mView is null)
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    ↓ ViewRootImpl.mActivityConfigCallback
06-20 18:40:32.018916 13804 30781 D LeakCanary: ├─ android.app.-$$Lambda$ActivityThread$ActivityClientRecord$HOrG1qglSjSUHSjKBn2rXtX0gGg
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    Leaking: YES (ViewRootImpl↑ is leaking)
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    ↓ -$$Lambda$ActivityThread$ActivityClientRecord$HOrG1qglSjSUHSjKBn2rXtX0gGg.f$0
06-20 18:40:32.018916 13804 30781 D LeakCanary: ├─ android.app.ActivityThread$ActivityClientRecord
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    Leaking: YES (-$$Lambda$ActivityThread$ActivityClientRecord$HOrG1qglSjSUHSjKBn2rXtX0gGg↑ is leaking)
06-20 18:40:32.018916 13804 30781 D LeakCanary: │    ↓ ActivityThread$ActivityClientRecord.activity
06-20 18:40:32.018916 13804 30781 D LeakCanary: ╰→ <>.MediaControlActivity
06-20 18:40:32.018916 13804 30781 D LeakCanary: ​     Leaking: YES (ActivityThread$ActivityClientRecord↑ is leaking and Activity#mDestroyed is true and ObjectWatcher was watching this)
06-20 18:40:32.018916 13804 30781 D LeakCanary: ​     key = c398c4b4-d254-4d0f-aaf7-c2d22687d27a
06-20 18:40:32.018916 13804 30781 D LeakCanary: ​     watchDurationMillis = 100672
06-20 18:40:32.018916 13804 30781 D LeakCanary: ​     retainedDurationMillis = 95672
06-20 18:40:32.018916 13804 30781 D LeakCanary: , retainedHeapByteSize=179995, pattern=instance field android.os.Message#next, description=A thread waiting on a blocking queue will leak the last dequeued object as a stack local reference. So when a HandlerThread becomes idle, it keeps a local reference to the last message it received. That message then gets recycled and can be used again. As long as all messages are recycled after being used, this won't be a problem, because these references are cleared when being recycled. However, dialogs create template Message instances to be copied when a message needs to be sent. These Message templates holds references to the dialog listeners, which most likely leads to holding a reference onto the activity in some way. Dialogs never recycle their template Message, assuming these Message instances will get GCed when the dialog is GCed. The combination of these two things creates a high potential for memory leaks as soon as you use dialogs. These memory leaks might be temporary, but some handler threads sleep for a long time. To fix this, you could post empty messages to the idle handler threads from time to time. This won't be easy because you cannot access all handler threads, but a library that is widely used should consider doing this for its own handler threads. This leaks has been shown to happen in both Dalvik and ART.)])

我无法确定原因。

堆栈跟踪中的一种可能性似乎是其中一个视图有一个可运行的计划运行,并且该视图最终持有对活动的引用。但 我没有看到任何可运行的内容被发布到视图中。 具体来说,我不太了解泄漏跟踪的最后 4 行。

【问题讨论】:

这发生在哪个版本的 Android 上?看起来像是 AOSP 泄漏。 这发生在最新的 wearOS 上。 【参考方案1】:

这是框架代码中的一个错误。

【讨论】:

以上是关于无法在泄漏金丝雀跟踪中找到原因的主要内容,如果未能解决你的问题,请参考以下文章

跟踪内存泄漏

了解 LeakCanary 内存泄漏堆栈跟踪

如何使用泄漏金丝雀

Android泄漏金丝雀日志

如何解决框架布局中的内存泄漏问题?

无法跟踪内存问题