我的 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
我不明白這里有什么問題。我postdelayed()
在ondestroy()
呼叫時關閉了所有方法。這是代碼:
@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以及如何關閉它的所有泄漏。提前致謝!
uj5u.com熱心網友回復:
什么是訊息佇列?
有 3 個關鍵的 Android 類系結在一起:Handler、Looper 和 MessageQueue。創建 Looper 實體時,它會創建自己的 MessageQueue 實體。然后你可以創建一個 Handler 并給它一個 Looper 實體。當您呼叫 Handler.post()(或 postDelayed)時,實際上您實際上是在呼叫 Handler.sendMessage,它將 Message 佇列上的 Message 實體排入佇列,該佇列與與該 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.when = 37524601 (681 ms after heap dump)
這告訴我們訊息被延遲排入佇列,并將在 681 毫秒內執行(在進行堆轉儲之后)
Message.callback = instance @319985112 of com.application.app.MainActivity$$ExternalSyntheticLambda2
這告訴我們排隊的回呼是 MainActivity 中定義的內部 lambda。很難弄清楚是哪個,但是如果您反編譯位元組碼(例如類檔案或 dex),您應該能夠分辨出哪個 lambda 具有該名稱。
使固定
最有可能的是,您有一段代碼,即使在活動被銷毀之后,它也會在主執行緒上將自身重新調度為 postDelayed。該回呼需要在 onDestroy() 中取消
編輯:注意在另一個答案中使用 Wea??kReference 的建議:這不是好的一般建議。來自檔案:https : //square.github.io/leakcanary/fundamentals-fixing-a-memory-leak/#4-fix-the-leak
無法通過用弱參考替換強參考來修復記憶體泄漏。當試圖快速解決記憶體問題時,這是一個常見的解決方案,但它永遠不會奏效。導致參考保存時間超過必要時間的錯誤仍然存??在。最重要的是,它會產生更多的錯誤,因為某些物件現在會比它們應該更早地被垃圾收集。它還使代碼更難維護。
uj5u.com熱心網友回復:
檢查您的 Activity 的所有資料成員,有一些資料成員比您的 Activity 生命周期更長。
還要檢查您在哪些地方傳遞活動背景關系和 MainActivity.this 實體。
最后檢查哪些回呼/ lambda 與此活動相關聯,可能有一種情況是您的類成員之一與其他類共享,例如回收器視圖配接器,這可能會導致泄漏。
作為處理記憶體泄漏問題的經驗法則,我封裝了大部分(如果不是全部)通過 WeakReference 傳遞的資料,這樣您既可以免受 NPE 的影響,又可以從解耦類中受益。
編輯- 正如在下面的評論中所分享的,使用弱參考是一種不好的做法,有更好的方法來解決記憶體泄漏。請檢查@Pierre 的答案或鏈接到下面發布的評論。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/393622.html