I'm using LeakCanary and it found a memory leak in ConnectivityManager. I've never used ConnectivityManager before and it's not in my project from anything that I wrote. I'm assuming maybe a 3rd party library is using it.
How can I fix this?
┬───
│ GC Root: System class
│
├─ android.net.ConnectivityManager class
│ Leaking: NO (a class is never leaking)
│ ↓ static ConnectivityManager.sCallbackHandler
│ ~~~~~~~~~~~~~~~~
├─ android.net.ConnectivityManager$CallbackHandler instance
│ Leaking: UNKNOWN
│ Retaining 32 B in 1 objects
│ ↓ ConnectivityManager$CallbackHandler.this$0
│ ~~~~~~
├─ android.net.ConnectivityManager instance
│ Leaking: UNKNOWN
│ Retaining 516.0 kB in 8048 objects
│ mContext instance of com.company.appname.MainActivity with mDestroyed =
│ true
│ ↓ ConnectivityManager.mContext
│ ~~~~~~~~
╰→ com.company.appname.MainActivity instance
Leaking: YES (ObjectWatcher was watching this because com.company.
appname.MainActivity received Activity#onDestroy() callback and
Activity#mDestroyed is true)
Retaining 515.9 kB in 8043 objects
key = fb405ad1-a78b-4e8f-8d09-c1b937e1462c
watchDurationMillis = 8341
retainedDurationMillis = 3230
mApplication instance of android.app.Application
mBase instance of androidx.appcompat.view.ContextThemeWrapper
@KevinCoppock sent me in the right direction
The memory leak culprit was AdMob
, specifically MobileAds.initialize(requireContext())
for banner ads which I used inside one of my fragments.
Once I changed it to use MobileAds.initialize(MyApplication.myAppContext)
, the leak no longer appeared. Here's an example:
1- AdMob initialization in Fragment example:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// MobileAds.initialize(requireContext()) <---- Causes Memory Leak
MobileAds.initialize(MyApplication.myAppContext) // <---- No Memory Leak
}
2- MyApplication class:
class MyApplication : Application() {
companion object {
lateinit var myAppContext: Context
}
override fun onCreate() {
super.onCreate()
myAppContext = applicationContext
}
}
Side note for beginners, make sure to add MyApplication to your Manifest as in android:name=".MyApplication"