android中消息队列内存泄漏?

Raf*_*afi 3 java android memory-leaks message-queue leakcanary

LeakCanary 检测到我的 MainActivity.java 中存在内存泄漏。这是我的泄漏痕迹。

\n
\xe2\x94\xac\xe2\x94\x80\xe2\x94\x80\xe2\x94\x80\n\xe2\x94\x82 GC Root: Input or output parameters in native code\n\xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80 android.os.MessageQueue instance\n\xe2\x94\x82    Leaking: NO (MessageQueue#mQuitting is false)\n\xe2\x94\x82    HandlerThread: "main"\n\xe2\x94\x82    \xe2\x86\x93 MessageQueue.mMessages\n\xe2\x94\x82                   ~~~~~~~~~\n\xe2\x94\x9c\xe2\x94\x80 android.os.Message instance\n\xe2\x94\x82    Leaking: UNKNOWN\n\xe2\x94\x82    Retaining 14.2 kB in 348 objects\n\xe2\x94\x82    Message.what = 0\n\xe2\x94\x82    Message.when = 37524601 (681 ms after heap dump)\n\xe2\x94\x82    Message.obj = null\n\xe2\x94\x82    Message.callback = instance @319985112 of com.application.app.\n\xe2\x94\x82    MainActivity$$ExternalSyntheticLambda2\n\xe2\x94\x82    \xe2\x86\x93 Message.callback\n\xe2\x94\x82              ~~~~~~~~\n\xe2\x94\x9c\xe2\x94\x80 com.application.app.MainActivity$$ExternalSyntheticLambda2 instance\n\xe2\x94\x82    Leaking: UNKNOWN\n\xe2\x94\x82    Retaining 12 B in 1 objects\n\xe2\x94\x82    f$0 instance of com.application.app.MainActivity with mDestroyed =\n\xe2\x94\x82    true\n\xe2\x94\x82    \xe2\x86\x93 MainActivity$$ExternalSyntheticLambda2.f$0\n\xe2\x94\x82                                             ~~~\n\xe2\x95\xb0\xe2\x86\x92 com.application.app.MainActivity instance\n      Leaking: YES (ObjectWatcher was watching this because com.defenderstudio.\n      geeksjob.MainActivity received Activity#onDestroy() callback and\n      Activity#mDestroyed is true)\n      Retaining 11.2 MB in 5622 objects\n      key = e98df529-afa0-4e0c-b0f0-51a5d3eaf67c\n      watchDurationMillis = 5249\n      retainedDurationMillis = 248\n      mApplication instance of android.app.Application\n      mBase instance of androidx.appcompat.view.ContextThemeWrapper\n\nMETADATA\n\nBuild.VERSION.SDK_INT: 30\nBuild.MANUFACTURER: samsung\nLeakCanary version: 2.7\nApp process name: com.application.app\nCount of retained yet cleared: 6 KeyedWeakReference instances\nStats: LruCache[maxSize=3000,hits=6544,misses=134885,hitRate=4%]\nRandomAccess[bytes=5904498,reads=134885,travel=75990168059,range=41137566,size=5\n3483782]\nHeap dump reason: 7 retained objects, app is visible\nAnalysis duration: 31639 ms\n
Run Code Online (Sandbox Code Playgroud)\n

我不明白这里有什么问题。我postdelayed()ondestroy()调用时关闭了所有方法。这是代码:

\n
@Override\nprotected void onDestroy() {\n    dialog = new Dialog(MainActivity.this, R.style.dialog);\n    if (dialog.isShowing()) {\n        dialog.dismiss();\n    }\n    if (handler != null && statusChecker != null) {\n        handler.removeCallbacks(statusChecker);\n    }\n    if (databaseReference != null && userSignInInfoReference != null && eventListener != null) {\n        databaseReference.removeEventListener(eventListener);\n        userSignInInfoReference.removeEventListener(eventListener);\n    }\n    progressDialog = new ProgressDialog(MainActivity.this, R.style.ProgressDialogStyle);\n    if (progressDialog.isShowing()) {\n        progressDialog.dismiss();\n    }\n    headerView = null;\n    super.onDestroy();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请帮帮我!

\n

注意:另外请告诉我什么是MessageQueue以及它的所有泄漏如何关闭。提前致谢!

\n

Pie*_*cau 8

什么是消息队列?

\n

有 3 个关键的 Android 类联系在一起:Handler、Looper 和 MessageQueue。当创建Looper实例时,它会创建自己的MessageQueue实例。然后你可以创建一个 Handler 并为其提供 Looper 实例。当您调用 Handler.post() (或 postDelayed)时,实际上是在调用 Handler.sendMessage,它将 Message 实例放入与该 Handler 关联的 Looper 关联的消息队列中。

\n

这些排队的消息会发生什么?在代码的其他地方(即专用的 HandlerThread),有东西调用 Looper.loop() ,它会永远循环,一次从关联的消息队列中删除一个条目并运行该消息。如果队列为空,则 Looper 等待下一条消息(通过本机代码完成)。更多上下文:https://developer.squareup.com/blog/a-journey-on-the-android-main-thread-psvm/

\n

我们可以从 LeakTrace 中读到什么?

\n

我们看到顶部的 MessageQueue 是用于以下 HandlerThread:“main”。这就是主线程。因此,如果您在主线程上执行 postDelayed,消息将被排队到消息队列中。

\n

消息存储为链表:MessageQueue 保存第一条消息(通过其 mMessages 字段),然后每条消息保存下一条消息。

\n

我们可以看到队列的头部是一个Message,我们可以看到它的内容。

\n

Message.when = 37524601 (681 ms after heap dump)

\n

这告诉我们消息已延迟排队,并将在 681 毫秒内执行(在进行堆转储之后)

\n

Message.callback = instance @319985112 of com.application.app.MainActivity$$ExternalSyntheticLambda2

\n

这告诉我们排队的回调是 MainActivity 中定义的内部 lambda。很难弄清楚是哪一个,但是如果您反编译字节码(例如类文件或 dex),您应该能够知道哪个 lambda 具有该名称。

\n

使固定

\n

最有可能的是,您有一段代码会不断将自身重新安排为主线程上的 postDelayed,即使在活动被销毁之后也是如此。该回调需要在 onDestroy() 中取消

\n

编辑:注意其他答案中使用 Wea​​kReference 的建议:这不是好的一般建议。来自文档:https://square.github.io/leakcanary/fundamentals-fixing-a-memory-leak/#4-fix-the-leak

\n
\n

内存泄漏无法通过用弱引用替换强引用来修复。当尝试快速解决内存问题时,它\xe2\x80\x99是一个常见的解决方案,但它从来没有起作用。导致引用保留时间超过必要时间的错误仍然存​​在。最重要的是,它会产生更多错误,因为某些对象现在会比应有的时间更快地被垃圾收集。这也使得代码更难维护。

\n
\n