Skip to content

Compose NavBackStackEntry leak #2675

Open

Description

Description

Hi all,

I'm getting a notification from Leakcanary when debugging an app on a Samsung Galaxy S10, running on Android 12.

Indeed, Leakcanary notifies a leaked activity when the concerned activity is recreated (toggling from light to night mode or vice versa, in my case).

Below are shown the content of the app MainActivity and the related Leakcanary report:

MainActivity.kt

@AndroidEntryPoint
class MainActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContent {
            val navController: NavHostController = rememberNavController()

            NavHost(
                navController = navController,
                startDestination = Destination.ONBOARDING.route
            ) {
                composable(
                    route = Destination.ONBOARDING.route
                ) {
                    Column(
                        modifier = Modifier.fillMaxSize(),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {

                        Text(text = resources().getString(com.everafrica.hanae.layout.R.string.exception_screen_title))

                        Text(text = resources().getString(com.everafrica.hanae.layout.R.string.exception_screen_description))

                        Button(onClick = {
                            
                        }) {
                            Text(text = resources().getString(com.everafrica.hanae.layout.R.string.exception_screen_button_text))
                        }

                    }
                }
            }
        }
    }

}

Leakcanary report

====================================
HEAP ANALYSIS RESULT
====================================
1 APPLICATION LEAKS

References underlined with "~" are likely causes.
Learn more at https://squ.re/leaks.

135737 bytes retained by leaking objects
Signature: 2f64fc5336e721e2d6c188105d82561500f0194c
┬───
│ GC Root: Thread object
│
├─ android.os.HandlerThread instance
│    Leaking: NO (PathClassLoader↓ is not leaking)
│    Thread name: 'queued-work-looper'
│    ↓ Thread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│    Leaking: NO (TransitionKt↓ is not leaking and A ClassLoader is never
│    leaking)
│    ↓ ClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│    Leaking: NO (TransitionKt↓ is not leaking)
│    ↓ Object[1198]
├─ androidx.compose.animation.core.TransitionKt class
│    Leaking: NO (a class is never leaking)
│    ↓ static TransitionKt.SeekableStateObserver$delegate
│                          ~~~~~~~~~~
├─ kotlin.UnsafeLazyImpl instance
│    Leaking: UNKNOWN
│    Retaining 16 B in 1 objects
│    ↓ UnsafeLazyImpl._value
│                     ~~
├─ androidx.compose.runtime.snapshots.SnapshotStateObserver instance
│    Leaking: UNKNOWN
│    Retaining 140,3 kB in 2776 objects
│    ↓ SnapshotStateObserver.observedScopeMaps
│                            ~~~~~~~
├─ androidx.compose.runtime.collection.MutableVector instance
│    Leaking: UNKNOWN
│    Retaining 140,2 kB in 2772 objects
│    ↓ MutableVector.content
│                    ~~~
├─ androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap[]
│  array
│    Leaking: UNKNOWN
│    Retaining 140,2 kB in 2771 objects
│    ↓ SnapshotStateObserver$ObservedScopeMap[0]
│                                            ~
├─ androidx.compose.runtime.snapshots.SnapshotStateObserver$ObservedScopeMap
│  instance
│    Leaking: UNKNOWN
│    Retaining 140,1 kB in 2770 objects
│    ↓ SnapshotStateObserver$ObservedScopeMap.scopeToValues
│                                             ~~~~~
├─ androidx.collection.MutableScatterMap instance
│    Leaking: UNKNOWN
│    Retaining 312 B in 12 objects
│    ↓ ScatterMap.keys
│                 ~~
├─ java.lang.Object[] array
│    Leaking: UNKNOWN
│    Retaining 28 B in 1 objects
│    ↓ Object[1]
│            ~
├─ androidx.compose.animation.core.SeekableTransitionState instance
│    Leaking: UNKNOWN
│    Retaining 139,2 kB in 2734 objects
│    ↓ SeekableTransitionState.composedTargetState
│                              ~~~~~~~
├─ androidx.navigation.NavBackStackEntry instance
│    Leaking: UNKNOWN
│    Retaining 137,7 kB in 2672 objects
│    context instance of com.app_package.hello_world.ui.container.MainActivity with
│    mDestroyed = true
│    ↓ NavBackStackEntry.context
│                        ~~~
╰→ com.app_package.hello_world.ui.container.MainActivity instance
​     Leaking: YES (ObjectWatcher was watching this because com.app_package.
​     hello_world.ui.container.MainActivity received Activity#onDestroy() callback
​     and Activity#mDestroyed is true)
​     Retaining 135,7 kB in 2609 objects
​     key = d2ae9775-0b51-4d98-83a3-cf91636dd049
​     watchDurationMillis = 9208
​     retainedDurationMillis = 4205
​     mApplication instance of com.app_package.hello_world.AppSingleton
​     mBase instance of android.app.ContextImpl
====================================
0 LIBRARY LEAKS

A Library Leak is a leak caused by a known bug in 3rd party code that you do
not have control over.
See https://square.github.
io/leakcanary/fundamentals-how-leakcanary-works/#4-categorizing-leaks
====================================
0 UNREACHABLE OBJECTS

An unreachable object is still in memory but LeakCanary could not find a strong
reference path
from GC roots.
====================================
METADATA

Please include this in bug reports and Stack Overflow questions.

Version Information

  • LeakCanary version: 3.0-alpha-4
  • Android OS version: 12
  • Gradle version: 8.4.0

Additional Information

In my opinion, this is a Leakcanary bug.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions