Description:
LeakCanary detected a memory leak in the nightly build. KiwixMainActivity is being retained in memory after being destroyed, due to a leak chain originating from Android's TextToSpeech system service connection.
Leak trace:
GC Root: Global variable in native code
android.speech.tts.TextToSpeech$SystemConnection$1 instance
Leaking: UNKNOWN
Retaining 1.0 MB in 12000 objects
Anonymous subclass of android.speech.tts.ITextToSpeechSessionCallback$Stub
(binder stub — retained until the other side is GCed)
↓ TextToSpeech$SystemConnection$1.this$1
android.speech.tts.TextToSpeech$SystemConnection instance
Leaking: UNKNOWN
Retaining 1.0 MB in 11999 objects
↓ TextToSpeech$SystemConnection.this$0
android.speech.tts.TextToSpeech instance
Leaking: UNKNOWN
Retaining 1.0 MB in 11997 objects
mContext instance of org.kiwix.kiwixmobile.main.KiwixMainActivity with mDestroyed = true
↓ TextToSpeech.mContext
org.kiwix.kiwixmobile.main.KiwixMainActivity instance
Leaking: YES (ObjectWatcher was watching this because
KiwixMainActivity received Activity#onDestroy() callback
and Activity#mDestroyed is true)
Retaining 1.0 MB in 11986 objects
watchDurationMillis = 5694
retainedDurationMillis = 693
Likely cause:
TextToSpeech holds a reference to the Context passed into its constructor (TextToSpeech.mContext). If KiwixMainActivity (or its Application/base Context) is passed in and the TextToSpeech instance is not released when the activity is destroyed, the underlying SystemConnection binder stub keeps the whole chain alive, preventing KiwixMainActivity from being garbage collected.
Suggested fix:
- Call
TextToSpeech.shutdown() in the appropriate lifecycle method (e.g. onDestroy()) of KiwixMainActivity or wherever the TextToSpeech instance is owned.
- Consider initializing
TextToSpeech with applicationContext instead of the activity context, to avoid tying its lifecycle to the activity.
Environment:
- Build: Kiwix nightly
- Detected by: LeakCanary
Description:
LeakCanary detected a memory leak in the nightly build.
KiwixMainActivityis being retained in memory after being destroyed, due to a leak chain originating from Android'sTextToSpeechsystem service connection.Leak trace:
Likely cause:
TextToSpeechholds a reference to theContextpassed into its constructor (TextToSpeech.mContext). IfKiwixMainActivity(or itsApplication/baseContext) is passed in and theTextToSpeechinstance is not released when the activity is destroyed, the underlyingSystemConnectionbinder stub keeps the whole chain alive, preventingKiwixMainActivityfrom being garbage collected.Suggested fix:
TextToSpeech.shutdown()in the appropriate lifecycle method (e.g.onDestroy()) ofKiwixMainActivityor wherever theTextToSpeechinstance is owned.TextToSpeechwithapplicationContextinstead of the activity context, to avoid tying its lifecycle to the activity.Environment: