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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions