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\nRun Code Online (Sandbox Code Playgroud)\n我不明白这里有什么问题。我postdelayed()在ondestroy()调用时关闭了所有方法。这是代码:
@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}\nRun Code Online (Sandbox Code Playgroud)\n请帮帮我!
\n注意:另外请告诉我什么是MessageQueue以及它的所有泄漏如何关闭。提前致谢!
\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我们看到顶部的 MessageQueue 是用于以下 HandlerThread:“main”。这就是主线程。因此,如果您在主线程上执行 postDelayed,消息将被排队到消息队列中。
\n消息存储为链表:MessageQueue 保存第一条消息(通过其 mMessages 字段),然后每条消息保存下一条消息。
\n我们可以看到队列的头部是一个Message,我们可以看到它的内容。
\nMessage.when = 37524601 (681 ms after heap dump)
这告诉我们消息已延迟排队,并将在 681 毫秒内执行(在进行堆转储之后)
\nMessage.callback = instance @319985112 of com.application.app.MainActivity$$ExternalSyntheticLambda2
这告诉我们排队的回调是 MainActivity 中定义的内部 lambda。很难弄清楚是哪一个,但是如果您反编译字节码(例如类文件或 dex),您应该能够知道哪个 lambda 具有该名称。
\n最有可能的是,您有一段代码会不断将自身重新安排为主线程上的 postDelayed,即使在活动被销毁之后也是如此。该回调需要在 onDestroy() 中取消
\n编辑:注意其他答案中使用 WeakReference 的建议:这不是好的一般建议。来自文档:https://square.github.io/leakcanary/fundamentals-fixing-a-memory-leak/#4-fix-the-leak
\n\n\n内存泄漏无法通过用弱引用替换强引用来修复。当尝试快速解决内存问题时,它\xe2\x80\x99是一个常见的解决方案,但它从来没有起作用。导致引用保留时间超过必要时间的错误仍然存在。最重要的是,它会产生更多错误,因为某些对象现在会比应有的时间更快地被垃圾收集。这也使得代码更难维护。
\n
| 归档时间: |
|
| 查看次数: |
1404 次 |
| 最近记录: |