Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Memory leaks from back navigation and reopening app from warm process state #238

Open
keithsmyth-thescore opened this issue Jan 9, 2025 · 3 comments

Comments

@keithsmyth-thescore
Copy link

keithsmyth-thescore commented Jan 9, 2025

For reproduction see fork: https://github.com/keithsmyth-thescore/TeadsSDK-android
code changes: keithsmyth-thescore@f25ff56

Leak Canary and Profiler both report memory leaks when following the reproduction steps below.

Reproduction steps:

  1. Open app in the fork
  2. Tap on RecyclerView button and scroll to load an ad
  3. Navigate back until the app is closed
  4. Reopen the app from task switcher or app drawer
  5. Leak Canary will start to analyse heap etc to report leaks

The leak we're experiencing in our application is the Thread.defaultUncaughtException one, details below

┬───
                 │ GC Root: System class
                 │
                 ├─ java.lang.Thread class
                 │    Leaking: NO (a class is never leaking)
                 │    ↓ static Thread.defaultUncaughtExceptionHandler
                 │                    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 ├─ tv.teads.sdk.utils.reporter.core.TeadsUncaughtExceptionHandler instance
                 │    Leaking: UNKNOWN
                 │    Retaining 42 B in 3 objects
                 │    ↓ TeadsUncaughtExceptionHandler.a
                 │                                    ~
                 ├─ tv.teads.sdk.utils.reporter.core.TeadsCrashController instance
                 │    Leaking: UNKNOWN
                 │    Retaining 2.2 kB in 68 objects
                 │    ↓ TeadsCrashController.f
                 │                           ~
                 ├─ tv.teads.sdk.utils.reporter.core.data.DataManager instance
                 │    Leaking: UNKNOWN
                 │    Retaining 1.9 kB in 60 objects
                 │    ↓ DataManager.b
                 │                  ~
                 ├─ android.app.ActivityManager instance
                 │    Leaking: UNKNOWN
                 │    Retaining 642 B in 5 objects
                 │    mContext instance of tv.teads.teadssdkdemo.MainActivity with mDestroyed = true
                 │    ↓ ActivityManager.mContext
                 │                      ~~~~~~~~
                 ╰→ tv.teads.teadssdkdemo.MainActivity instance
                 ​     Leaking: YES (ObjectWatcher was watching this because tv.teads.teadssdkdemo.MainActivity received
                 ​     Activity#onDestroy() callback and Activity#mDestroyed is true)
                 ​     Retaining 2.1 MB in 5485 objects
                 ​     key = 49740aaf-4857-420d-9173-45bbc147091f
                 ​     watchDurationMillis = 5202
                 ​     retainedDurationMillis = 199
                 ​     mApplication instance of android.app.Application
                 ​     mBase instance of androidx.appcompat.view.ContextThemeWrapper
                 
                 METADATA
                 
                 Build.VERSION.SDK_INT: 35
                 Build.MANUFACTURER: Google
                 LeakCanary version: 2.14
                 App process name: tv.teads.teadssdkdemo
                 Class count: 35653
                 Instance count: 251063
                 Primitive array count: 178776
                 Object array count: 31964
                 Thread count: 107
                 Heap total bytes: 37549779
                 Bitmap count: 5
                 Bitmap total bytes: 7291381
                 Large bitmap count: 0
                 Large bitmap total bytes: 0
                 Db 1: open /data/user/0/tv.teads.teadssdkdemo/no_backup/androidx.work.workdb
                 Db 2: closed /data/user/0/tv.teads.teadssdkdemo/databases/google_app_measurement_local.db
                 Db 3: closed /data/user/0/tv.teads.teadssdkdemo/databases/google_app_measurement_local.db
                 Db 4: closed /data/user/0/tv.teads.teadssdkdemo/databases/google_app_measurement_local.db
                 Count of retained yet cleared: 3 KeyedWeakReference instances
                 Stats: LruCache[maxSize=3000,hits=135323,misses=229018,hitRate=37%]
                 RandomAccess[bytes=11633522,reads=229018,travel=125974184036,range=44987490,size=54572480]
                 Analysis duration: 5564 ms
@teads-mattis-toutain
Copy link
Contributor

Hi @keithsmyth-thescore,

The leak you are mentionning is already known internally and is purely a matter of code structure that we are currently re-architecturing. Also the issue is amplified by the fact that the leaking activity (our demo MainActivity) is actually passed to the SDK (in place of a Context) at multiple occasions in our demo repo. Ie : this line of InReadScrollViewFragment.

You should be fine using the SDK in your apps as long as you don't pass activities in place of contexts.

@keithsmyth-thescore
Copy link
Author

Thanks very much @teads-mattis-toutain. It's good to hear a fix is on the way. Could you ping this thread when it's ready in case I miss it?

To make sure I understand, passing in applicationContext to a call like below would still function correctly, and would at least improve the leak situation?

From

adPlacement = TeadsSDK.createInReadPlacement(requireActivity(), pid, placementSettings)

To

adPlacement = TeadsSDK.createInReadPlacement(context.applicationContext, pid, placementSettings)

@teads-mattis-toutain
Copy link
Contributor

@keithsmyth-thescore I'll let you know when the fix is released.

And you're right, at least switching from activity inherited context to applicationContext will, in most cases, avoid potential leaks.

Let me know if you have any other question or issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants