我的www.example.com中有一个内存泄漏MainActivity.java,这是由LeakCanary检测到的。这是我的泄漏跟踪。
┬───
│ 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
我不明白这里出了什么问题,我在ondestroy()
被调用的时候关闭了所有的postdelayed()
方法,代码如下:
@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();
}
请帮帮我!
注意:也请告诉我什么是MessageQueue以及如何关闭它的所有泄漏。提前感谢!
3条答案
按热度按时间mfuanj7w1#
什么是消息队列?
有3个关键的Android类捆绑在一起:Handler、Looper和MessageQueue。当创建Looper示例时,它会创建自己的MessageQueue示例。然后,您可以创建一个Handler并将Looper示例给予它。当您调用Handler.post()(或postDelayed)时,实际上是在后台调用Handler.sendMessage,它将消息示例入队到与该Handler关联的Looper关联的消息队列中。
那些排队的消息会发生什么?在代码的其他地方(例如专用的HandlerThread),有东西调用Looper.loop(),它会永远循环,一次从关联的Message队列中删除一个条目并运行该消息。如果队列为空,Looper会等待下一条消息(通过本机代码完成)。更多上下文:https://developer.squareup.com/blog/a-journey-on-the-android-main-thread-psvm/
我们可以从LeakTrace中读取什么?
我们可以看到顶部的MessageQueue用于以下HandlerThread:“main”。这是主线程。所以如果你在主线程上执行postDelayed,一条消息就会被加入到消息队列中。
消息存储为链接列表:MessageQueue保持第一消息(经由其mMessages字段),然后每个消息保持下一消息。
我们可以看到队列的头部是一个Message,并且可以看到它的内容。
Message.when = 37524601 (681 ms after heap dump)
这告诉我们消息排队时有延迟,将在681ms内执行(在进行堆转储之后)
Message.callback = instance @319985112 of com.application.app.MainActivity$$ExternalSyntheticLambda2
这告诉我们排队的回调是在MainActivity中定义的一个内部lambda,很难判断是哪一个,但是如果你反编译字节码(例如class文件或dex),你应该能够分辨出哪个lambda有这个名字。
修复
最有可能的情况是,您有一段代码在主线程上不断地将自己重新调度为postDelayed,即使在Activity被销毁之后也是如此。
编辑:注意另一个答案中使用WeakReference的建议:这可不是个好建议。医生说:https://square.github.io/leakcanary/fundamentals-fixing-a-memory-leak/#4-fix-the-leak
内存泄漏不能通过用弱引用替换强引用来修复。当试图快速解决内存问题时,这是一个常见的解决方案,但是它从来没有工作过。导致引用保留时间过长的bug仍然存在。除此之外,它还导致了更多的bug,因为一些对象现在将比它们应该的更早被垃圾收集。它还使代码更难维护。
w8f9ii692#
检查Activity的所有数据成员,确定是否存在一些超过Activity生命周期的数据成员。
还要检查您传递活动上下文和MainActivity.this示例的位置。
最后,检查哪些回调/ lambda与此活动相关联,可能会有这样的情况,即您的类的成员之一与其他一些类(如回收器视图适配器)共享,这可能会导致泄漏。
在处理内存泄漏问题时,作为一个经验法则,我使用WeakReference封装大多数(如果不是所有)数据传递,这样既可以避免NPE,又可以从解耦的类中获益。
编辑-正如下面的评论中所分享的,使用弱引用是一种不好的做法,有更好的方法来解决内存泄漏。请检查@Pierre的答案或链接到下面的评论。
bnlyeluc3#
如果您需要快速修复,我自己测试并成功解决此问题的最简单直接的方法是使用此magic库WeakHandler
如果你需要阅读更多的check here
这是一个示例代码
在build gradle中,添加以下库
然后