Skip to content

Memory leak when ActivityProvider is provided to Superwall.configure #245

@fibelatti

Description

@fibelatti

Hi folks, we started observing memory leaks coming from Superwall because it seem to be retaining a reference to destroyed activities. Details below.


Superwall SDK version: 2.1.0

Call site:

Superwall.configure(
  applicationContext = application,
  apiKey = <API KEY>,
  activityProvider = object : ActivityProvider {

    override fun getCurrentActivity(): Activity? = activityProvider.currentActivity?.get()
  },
  purchaseController = purchaseController,
)

For reference, activityProvider is an implementation of:

public interface ActivityReferenceProvider {

  public val currentActivity: WeakReference<Activity>?
}

Memory leak dump:

┬───
│ GC Root: Thread object
│
├─ android.net.ConnectivityThread instance
│    Leaking: NO (PathClassLoader↓ is not leaking)
│    Thread name: 'ConnectivityThread'
│    ↓ Thread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│    Leaking: NO (Superwall↓ is not leaking and A ClassLoader is never leaking)
│    ↓ ClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│    Leaking: NO (Superwall↓ is not leaking)
│    ↓ Object[12102]
├─ com.superwall.sdk.Superwall class
│    Leaking: NO (a class is never leaking)
│    ↓ static Superwall._instance
│                       ~~~~~~~~~
├─ com.superwall.sdk.Superwall instance
│    Leaking: UNKNOWN
│    Retaining 1.0 kB in 45 objects
│    context instance of <Application Class>
│    ↓ Superwall._dependencyContainer
│                ~~~~~~~~~~~~~~~~~~~~
├─ com.superwall.sdk.dependencies.DependencyContainer instance
│    Leaking: UNKNOWN
│    Retaining 3.6 kB in 132 objects
│    context instance of <Application Class>
│    ↓ DependencyContainer.paywallManager
│                          ~~~~~~~~~~~~~~
├─ com.superwall.sdk.paywall.manager.PaywallManager instance
│    Leaking: UNKNOWN
│    Retaining 24 B in 1 objects
│    ↓ PaywallManager._cache
│                     ~~~~~~
├─ com.superwall.sdk.paywall.manager.PaywallViewCache instance
│    Leaking: UNKNOWN
│    Retaining 177 B in 5 objects
│    appCtx instance of <Application Class>
│    ↓ PaywallViewCache.shimmerView
│                       ~~~~~~~~~~~
├─ com.superwall.sdk.paywall.view.ShimmerView instance
│    Leaking: UNKNOWN
│    Retaining 202.1 kB in 4017 objects
│    View not part of a window view hierarchy
│    View.mAttachInfo is null (view detached)
│    View.mWindowAttachCount = 0
│    mContext instance of <Application Class>
│    ↓ ShimmerView.landscapeDrawable$delegate
│                  ~~~~~~~~~~~~~~~~~~~~~~~~~~
├─ kotlin.SynchronizedLazyImpl instance
│    Leaking: UNKNOWN
│    Retaining 181.7 kB in 3613 objects
│    ↓ SynchronizedLazyImpl.initializer
│                           ~~~~~~~~~~~
├─ com.superwall.sdk.paywall.view.ShimmerView$$ExternalSyntheticLambda2 instance
│    Leaking: UNKNOWN
│    Retaining 181.7 kB in 3612 objects
│    f$0 instance of <Activity Class> with
│    mDestroyed = true
│    ↓ ShimmerView$$ExternalSyntheticLambda2.f$0
│                                            ~~~
╰→ <Activity Class> instance
​     Leaking: YES (ObjectWatcher was watching this because <Activity Class> received Activity#onDestroy() callback and
​     Activity#mDestroyed is true)
​     Retaining 181.7 kB in 3611 objects
​     key = feac19bd-77b1-4295-9d3f-df14c1a4076a
​     watchDurationMillis = 5555
​     retainedDurationMillis = 552
​     mApplication instance of <Application Class>
​     mBase instance of androidx.appcompat.view.ContextThemeWrapper

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions