3

I'm using LeakCanary but the heap analysis result doesn't provide enough information to detect any leak. It only mentions that the activity is leaking.

D/LeakCanary: ​
    ====================================
    HEAP ANALYSIS RESULT
    ====================================
    1 APPLICATION LEAKS
    
    References underlined with "~~~" are likely causes.
    Learn more at https://squ.re/leaks.
    
    298153 bytes retained by leaking objects
    Signature: a610bac3ef989ac5dc5a69244fc2882de5617
    ┬───
    │ GC Root: System class
    │
    ├─ android.provider.FontsContract class
    │    Leaking: NO (MyApplication↓ is not leaking and a class is never leaking)
    │    ↓ static FontsContract.sContext
    ├─ com.example.MyApplication instance
    │    Leaking: NO (Application is a singleton)
    │    mBoundService instance of com.example.services.SessionService
    │    mBase instance of android.app.ContextImpl
    │    ↓ Application.mLoadedApk
    │                  ~~~~~~~~~~
    ├─ android.app.LoadedApk instance
    │    Leaking: UNKNOWN
    │    Retaining 302.8 kB in 4641 objects
    │    mApplication instance of com.example.MyApplication
    │    ↓ LoadedApk.mReceivers
    │                ~~~~~~~~~~
    ├─ android.util.ArrayMap instance
    │    Leaking: UNKNOWN
    │    Retaining 301.7 kB in 4615 objects
    │    ↓ ArrayMap.mArray
    │               ~~~~~~
    ├─ java.lang.Object[] array
    │    Leaking: UNKNOWN
    │    Retaining 301.7 kB in 4613 objects
    │    ↓ Object[].[2]
    │               ~~~
    ╰→ com.example.activities.SelectActivity instance
    ​     Leaking: YES (ObjectWatcher was watching this because com.example.activities.SelectActivity received
    ​     Activity#onDestroy() callback and Activity#mDestroyed is true)
    ​     Retaining 298.2 kB in 4579 objects
    ​     key = 68660c30-bc17-4a74-a5e2-c54f6d676c59
    ​     watchDurationMillis = 5185
    ​     retainedDurationMillis = 183
    ​     mApplication instance of com.example.MyApplication
    ​     mBase instance of androidx.appcompat.view.ContextThemeWrapper
    ====================================
    0 LIBRARY LEAKS

All I know from this trace is SelectActivity is leaking. But I can't figure out why? The activity itself is 1000+ lines and I was hoping if there's any shortcut other than going though every line and checking for a possible leak candidate.

Shivam Pokhriyal
  • 1,044
  • 11
  • 26
  • 1
    Try to change find where `this` (as context) has used in the activity and check multithreading lines. I suggest refactor it and try to use ViewModel and other patterns to reduce the activity lines of code. Otherwise, I hope God helps :D – beigirad Mar 15 '21 at 15:32
  • haha. I've been trying for a couple days now. I've removed almost everything from the activity except for the adapter and the async task and those don't have any reference to the activity as well. But still it's leaking. Is there any other way to get a better trace of the leak? The above trace is of no help at all. – Shivam Pokhriyal Mar 15 '21 at 16:37

1 Answers1

5

Does the activity register any broadcast receiver? The leaktrace shows LoadedApk.mReceivers which is an ArrayMap of receivers to receiver dispatcher and the activity is the receiver dispatcher.

Pierre-Yves Ricau
  • 8,209
  • 2
  • 27
  • 43
  • No it doesn't use any receiver now. It was using a location listener earlier, but I removed it completely and it's still leaking somewhere :( – Shivam Pokhriyal Mar 15 '21 at 04:43
  • You were correct indeed. There was a base activity which was registering a receiver twice and causing this leak. Thanks! – Shivam Pokhriyal Mar 16 '21 at 10:20
  • 1
    Thx! Can you file an issue at https://github.com/square/leakcanary/issues/new/choose ? I'll check if I can repro and if yes see if I can make the error more obvious if others run into it. Also feel free to validate the answer :) – Pierre-Yves Ricau Mar 17 '21 at 16:39
  • Update: I filed here: https://github.com/square/leakcanary/issues/2091 – Pierre-Yves Ricau Mar 18 '21 at 23:57
  • Ohh so sorry I missed your last message. But thanks for filing. To add more info, the register was getting registered in `onResume` and `onActivityResult` and was getting unregistered in `onPause`. And this was all in base activity which is why I missed this in the first place. – Shivam Pokhriyal Mar 20 '21 at 04:31
  • I'll see if I can create a minimal reproducible sample to repro this issue and will comment it in the issue itself. Thanks! – Shivam Pokhriyal Mar 20 '21 at 04:36