简体   繁体   English

Memory android 中的 MessageQueue 泄漏?

[英]Memory Leak in MessageQueue in android?

I am having a memory leak in my MainActivity.java which was detected by LeakCanary.我的 MainActivity.java 中有一个 memory 泄漏,它被 LeakCanary 检测到。 This is my Leak Trace.这是我的泄漏跟踪。

┬───
│ GC Root: Input or output parameters in native code
│
├─ android.os.MessageQueue instance
│    Leaking: NO (MessageQueue#mQuitting is false)
│    HandlerThread: "main"
│    ↓ MessageQueue.mMessages
│                   ~~~~~~~~~
├─ android.os.Message instance
│    Leaking: UNKNOWN
│    Retaining 14.2 kB in 348 objects
│    Message.what = 0
│    Message.when = 37524601 (681 ms after heap dump)
│    Message.obj = null
│    Message.callback = instance @319985112 of com.application.app.
│    MainActivity$$ExternalSyntheticLambda2
│    ↓ Message.callback
│              ~~~~~~~~
├─ com.application.app.MainActivity$$ExternalSyntheticLambda2 instance
│    Leaking: UNKNOWN
│    Retaining 12 B in 1 objects
│    f$0 instance of com.application.app.MainActivity with mDestroyed =
│    true
│    ↓ MainActivity$$ExternalSyntheticLambda2.f$0
│                                             ~~~
╰→ com.application.app.MainActivity instance
      Leaking: YES (ObjectWatcher was watching this because com.defenderstudio.
      geeksjob.MainActivity received Activity#onDestroy() callback and
      Activity#mDestroyed is true)
      Retaining 11.2 MB in 5622 objects
      key = e98df529-afa0-4e0c-b0f0-51a5d3eaf67c
      watchDurationMillis = 5249
      retainedDurationMillis = 248
      mApplication instance of android.app.Application
      mBase instance of androidx.appcompat.view.ContextThemeWrapper

METADATA

Build.VERSION.SDK_INT: 30
Build.MANUFACTURER: samsung
LeakCanary version: 2.7
App process name: com.application.app
Count of retained yet cleared: 6 KeyedWeakReference instances
Stats: LruCache[maxSize=3000,hits=6544,misses=134885,hitRate=4%]
RandomAccess[bytes=5904498,reads=134885,travel=75990168059,range=41137566,size=5
3483782]
Heap dump reason: 7 retained objects, app is visible
Analysis duration: 31639 ms

I can't understand what is the problem here.我不明白这里有什么问题。 I closed all the postdelayed() method when ondestroy() is called.调用ondestroy() () 时,我关闭了所有postdelayed()方法。 This is the code:这是代码:

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

Please help me out here!请帮帮我!

NOTE: Also Please tell me what is MessageQueue and how close all leaks of it.注意:另外请告诉我什么是MessageQueue以及它的所有泄漏有多接近。 Thanks in advance!提前致谢!

Check all the data members of your Activity there is some data member which is outliving your activity's lifecycle.检查 Activity 的所有数据成员,有一些数据成员超过了 Activity 的生命周期。

Also check in what places you are passing the activity context and MainActivity.this instance.还要检查您传递活动上下文和 MainActivity.this 实例的位置。

Lastly check what callbacks / lambda's are associated with this activity there could be a case that one of your class's member is being shared with some other class like a recycler view adapter which could lead to a leak.最后检查哪些回调/ lambda 与此活动相关联,可能存在这样一种情况,即您的班级成员之一正在与其他一些 class 共享,例如可能导致泄漏的回收器视图适配器。

As a thumb rule when working on memory leak issues I encapsulate most if not all data passing with WeakReference that way you are both safe from NPE plus you get benefit of a decoupled class.作为处理 memory 泄漏问题时的经验法则,我封装了大多数(如果不是所有)通过 WeakReference 传递的数据,这样您既可以安全地免受 NPE 影响,又可以从解耦的 class 中受益。

What is a MessageQueue?什么是消息队列?

There are 3 key Android classes tied together: Handler, Looper and MessageQueue.有 3 个关键的 Android 类捆绑在一起:Handler、Looper 和 MessageQueue。 Wheb a Looper instance is created, it creates its own MessageQueue instance.当创建 Looper 实例时,它会创建自己的 MessageQueue 实例。 Then you can create a Handler et pass it the Looper instance.然后你可以创建一个 Handler 并将 Looper 实例传递给它。 When you call Handler.post() (or postDelayed), under the hood you're actually calling Handler.sendMessage which enqueues a Message instance on the Message queue associated to the Looper associated to that Handler.当您调用 Handler.post()(或 postDelayed)时,实际上是在调用 Handler.sendMessage,它在与该 Handler 关联的 Looper 关联的消息队列中加入一个 Message 实例。

What happens to those enqueued messages?这些排队的消息会发生什么? Somewhere else in the code (ie dedicated HandlerThread), something calls Looper.loop() which loops forever, removing one entry at a time from the associated Message queue and running that message.在代码中的其他地方(即专用的 HandlerThread),调用 Looper.loop() 的东西永远循环,从关联的消息队列中一次删除一个条目并运行该消息。 If the queue is empty, the Looper waits for the next message (that's done via native code).如果队列为空,Looper 将等待下一条消息(这是通过本机代码完成的)。 Some more context: https://developer.squareup.com/blog/a-journey-on-the-android-main-thread-psvm/更多上下文: https://developer.squareup.com/blog/a-journey-on-the-android-main-thread-psvm/

What can we read from the LeakTrace?我们可以从 LeakTrace 中读取什么信息?

We see that the MessageQueue at the top is for the following HandlerThread: "main".我们看到顶部的 MessageQueue 是针对以下 HandlerThread:“main”的。 That's the main thread.这就是主线。 So if you're doing a postDelayed on the main thread, a message gets enqueued into the message queue.因此,如果您在主线程上执行 postDelayed,则会将消息排入消息队列。

Messages are stored as a linked list: the MessageQueue holds on to the first message (via its mMessages field) and then each message holds on to the next.消息以链表的形式存储:MessageQueue 保留第一条消息(通过其 mMessages 字段),然后每条消息都保留下一条。

We can see that the head of the queue is a Message and we can see its content.我们可以看到队列的头部是一个Message,我们可以看到它的内容。

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

This tells us the message was enqueued with a delay and will execute in 681ms (after the heap dump was taken)这告诉我们消息被延迟排队并将在 681 毫秒内执行(在进行堆转储之后)

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

This tells us the callback enqueued is an inner lambda defined in MainActivity.这告诉我们入队的回调是 MainActivity 中定义的内部 lambda。 It's hard to figure out which one, but if you decompile the bytecode (eg class files or dex) you should be able to tell which lambda has that name.很难确定是哪一个,但是如果您反编译字节码(例如 class 文件或 dex),您应该能够分辨出哪个 lambda 具有该名称。

Fix使固定

Most likely, you have a piece a code that keeps rescheduling itself as a postDelayed on the main thread, even after the activity is destroyed.最有可能的是,您有一段代码在主线程上不断地重新安排自己作为 postDelayed,即使在活动被破坏之后也是如此。 That callback needs to be canceled in onDestroy()该回调需要在 onDestroy() 中取消

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM