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

Compose NavBackStackEntry leak #2675

Open
andronaline opened this issue May 13, 2024 · 4 comments
Open

Compose NavBackStackEntry leak #2675

andronaline opened this issue May 13, 2024 · 4 comments

Comments

@andronaline
Copy link

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.

@pyricau
Copy link
Member

pyricau commented May 21, 2024

This looks like a bug in Compose, maybe tied to SeekableTransitionState. Can you file a Compose issue on https://issuetracker.google.com/ , ideally with a small project to repro, and then share the link to the issue back here?

@andronaline
Copy link
Author

andronaline commented May 26, 2024

Hi Pyricau,

Thank you for your reply.

Here is the link of the Compose issue filed on the suggested url :
https://issuetracker.google.com/issues/342701252

@Ixam97
Copy link

Ixam97 commented Aug 1, 2024

I have faced a very similar issue in my project, that also seems to have originated from SeekableTransitionState in combination with navigation-compose. I now updated navigation-compose to version 2.8.0-beta06. The leak is now no longer an issue for me. Maybe you sould give it another try too.

@sebaslogen
Copy link

I also experience this issue in a sample app of https://github.com/sebaslogen/resaca
Updating to Navigation 2.8.0-rc01 also solved the problem for me

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

No branches or pull requests

4 participants