bonsai
bonsai copied to clipboard
Memory Leak possibly due to no proper `disposing` of `Composition`
I am facing a memory leak when using this library. I think it's probably due to the Composition
used in bonsai/core/tree/Tree.kt.
There is a method for disposing the composition (composition.dispose()
) which isn't getting called. It would be great if you can have a look at it.
Tried adding myComposeView.disposeComposition()
in onStop()
of Fragment, but got no luck.
Leakcanary Stacktrace
D/LeakCanary:
D/LeakCanary: ====================================
D/LeakCanary: HEAP ANALYSIS RESULT
D/LeakCanary: ====================================
D/LeakCanary: 3 APPLICATION LEAKS
D/LeakCanary:D/LeakCanary: References underlined with "~~~" are likely causes.
D/LeakCanary: Learn more at https://squ.re/leaks.
D/LeakCanary:D/LeakCanary: 2794 bytes retained by leaking objects
D/LeakCanary: Signature: 294c14f86ef1f535d2d18c00e3aefe49abd3e220
D/LeakCanary: ┬───
D/LeakCanary: │ GC Root: Input or output parameters in native code
D/LeakCanary: │
D/LeakCanary: ├─ dalvik.system.PathClassLoader instance
D/LeakCanary: │ Leaking: NO (SnapshotKt↓ is not leaking and A ClassLoader is never leaking)
D/LeakCanary: │ ↓ ClassLoader.runtimeInternalObjects
D/LeakCanary: ├─ java.lang.Object[] array
D/LeakCanary: │ Leaking: NO (SnapshotKt↓ is not leaking)
D/LeakCanary: │ ↓ Object[6667]
D/LeakCanary: ├─ androidx.compose.runtime.snapshots.SnapshotKt class
D/LeakCanary: │ Leaking: NO (Recomposer↓ is not leaking and a class is never leaking)
D/LeakCanary: │ ↓ static SnapshotKt.applyObservers
D/LeakCanary: ├─ java.util.ArrayList instance
D/LeakCanary: │ Leaking: NO (Recomposer↓ is not leaking)
D/LeakCanary: │ ↓ ArrayList[0]
D/LeakCanary: ├─ androidx.compose.runtime.Recomposer$recompositionRunner$2$unregisterApplyObserver$1 instance
D/LeakCanary: │ Leaking: NO (Recomposer↓ is not leaking)
D/LeakCanary: │ Anonymous subclass of kotlin.jvm.internal.Lambda
D/LeakCanary: │ ↓ Recomposer$recompositionRunner$2$unregisterApplyObserver$1.this$0
D/LeakCanary: ├─ androidx.compose.runtime.Recomposer instance
D/LeakCanary: │ Leaking: NO (CompositionImpl↓ is not leaking and Recomposer is in state Idle)
D/LeakCanary: │ ↓ Recomposer.knownCompositions
D/LeakCanary: ├─ java.util.ArrayList instance
D/LeakCanary: │ Leaking: NO (CompositionImpl↓ is not leaking)
D/LeakCanary: │ ↓ ArrayList[0]
D/LeakCanary: ├─ androidx.compose.runtime.CompositionImpl instance
D/LeakCanary: │ Leaking: NO (Composition not disposed)
D/LeakCanary: │ ↓ CompositionImpl.composer
D/LeakCanary: │ ~~~~~~~~
D/LeakCanary: ├─ androidx.compose.runtime.ComposerImpl instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 9.1 kB in 48 objects
D/LeakCanary: │ ↓ ComposerImpl.parentProvider
D/LeakCanary: │ ~~~~~~~~~~~~~~
D/LeakCanary: ├─ androidx.compose.runtime.external.kotlinx.collections.immutable.implementations.immutableMap.PersistentHashMap
D/LeakCanary: │ instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 320 B in 8 objects
D/LeakCanary: │ ↓ PersistentHashMap.node
D/LeakCanary: │ ~~~~
D/LeakCanary: ├─ androidx.compose.runtime.external.kotlinx.collections.immutable.implementations.immutableMap.TrieNode instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 296 B in 7 objects
D/LeakCanary: │ ↓ TrieNode.buffer
D/LeakCanary: │ ~~~~~~
D/LeakCanary: ├─ java.lang.Object[] array
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 272 B in 6 objects
D/LeakCanary: │ ↓ Object[45]
D/LeakCanary: │ ~~~~
D/LeakCanary: ├─ androidx.compose.runtime.StaticValueHolder instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 12 B in 1 objects
D/LeakCanary: │ ↓ StaticValueHolder.value
D/LeakCanary: │ ~~~~~
D/LeakCanary: ├─ androidx.fragment.app.FragmentViewLifecycleOwner instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 173 B in 6 objects
D/LeakCanary: │ ↓ FragmentViewLifecycleOwner.mFragment
D/LeakCanary: │ ~~~~~~~~~
D/LeakCanary: ╰→ dev.yashgarg.qbit.ui.torrent.tabs.TorrentFilesFragment instance
D/LeakCanary: Leaking: YES (ObjectWatcher was watching this because dev.yashgarg.qbit.ui.torrent.tabs.TorrentFilesFragment
D/LeakCanary: received Fragment#onDestroy() callback and Fragment#mFragmentManager is null)
D/LeakCanary: Retaining 2.8 kB in 105 objects
D/LeakCanary: key = 729161f9-e2c4-4211-a526-d0a54992cd9e
D/LeakCanary: watchDurationMillis = 5484
D/LeakCanary: retainedDurationMillis = 483
D/LeakCanary:D/LeakCanary: 210 bytes retained by leaking objects
D/LeakCanary: Signature: cd1c7c9324750e1908bfb93e73a7daaccc8ddf30
D/LeakCanary: ┬───
D/LeakCanary: │ GC Root: Input or output parameters in native code
D/LeakCanary: │
D/LeakCanary: ├─ dalvik.system.PathClassLoader instance
D/LeakCanary: │ Leaking: NO (SnapshotKt↓ is not leaking and A ClassLoader is never leaking)
D/LeakCanary: │ ↓ ClassLoader.runtimeInternalObjects
D/LeakCanary: ├─ java.lang.Object[] array
D/LeakCanary: │ Leaking: NO (SnapshotKt↓ is not leaking)
D/LeakCanary: │ ↓ Object[6667]
D/LeakCanary: ├─ androidx.compose.runtime.snapshots.SnapshotKt class
D/LeakCanary: │ Leaking: NO (Recomposer↓ is not leaking and a class is never leaking)
D/LeakCanary: │ ↓ static SnapshotKt.applyObservers
D/LeakCanary: ├─ java.util.ArrayList instance
D/LeakCanary: │ Leaking: NO (Recomposer↓ is not leaking)
D/LeakCanary: │ ↓ ArrayList[0]
D/LeakCanary: ├─ androidx.compose.runtime.Recomposer$recompositionRunner$2$unregisterApplyObserver$1 instance
D/LeakCanary: │ Leaking: NO (Recomposer↓ is not leaking)
D/LeakCanary: │ Anonymous subclass of kotlin.jvm.internal.Lambda
D/LeakCanary: │ ↓ Recomposer$recompositionRunner$2$unregisterApplyObserver$1.this$0
D/LeakCanary: ├─ androidx.compose.runtime.Recomposer instance
D/LeakCanary: │ Leaking: NO (CompositionImpl↓ is not leaking and Recomposer is in state Idle)
D/LeakCanary: │ ↓ Recomposer.knownCompositions
D/LeakCanary: ├─ java.util.ArrayList instance
D/LeakCanary: │ Leaking: NO (CompositionImpl↓ is not leaking)
D/LeakCanary: │ ↓ ArrayList[0]
D/LeakCanary: ├─ androidx.compose.runtime.CompositionImpl instance
D/LeakCanary: │ Leaking: NO (Composition not disposed)
D/LeakCanary: │ ↓ CompositionImpl.slotTable
D/LeakCanary: │ ~~~~~~~~~
D/LeakCanary: ├─ androidx.compose.runtime.SlotTable instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 345 B in 17 objects
D/LeakCanary: │ ↓ SlotTable.slots
D/LeakCanary: │ ~~~~~
D/LeakCanary: ├─ java.lang.Object[] array
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 6.4 kB in 206 objects
D/LeakCanary: │ ↓ Object[32]
D/LeakCanary: │ ~~~~
D/LeakCanary: ├─ androidx.compose.ui.platform.DisposableSaveableStateRegistry instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 37 B in 2 objects
D/LeakCanary: │ ↓ DisposableSaveableStateRegistry.onDispose
D/LeakCanary: │ ~~~~~~~~~
D/LeakCanary: ├─ androidx.compose.ui.platform.DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$1 instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 21 B in 1 objects
D/LeakCanary: │ Anonymous subclass of kotlin.jvm.internal.Lambda
D/LeakCanary: │ ↓ DisposableSaveableStateRegistry_androidKt$DisposableSaveableStateRegistry$1.$androidxRegistry
D/LeakCanary: │ ~~~~~~~~~~~~~~~~~
D/LeakCanary: ├─ androidx.savedstate.SavedStateRegistry instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 506 B in 19 objects
D/LeakCanary: │ ↓ SavedStateRegistry.components
D/LeakCanary: │ ~~~~~~~~~~
D/LeakCanary: ├─ androidx.arch.core.internal.SafeIterableMap instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 483 B in 18 objects
D/LeakCanary: │ ↓ SafeIterableMap["androidx.lifecycle.internal.SavedStateHandlesProvider"]
D/LeakCanary: │ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
D/LeakCanary: ├─ androidx.lifecycle.SavedStateHandlesProvider instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 251 B in 10 objects
D/LeakCanary: │ ↓ SavedStateHandlesProvider.viewModel$delegate
D/LeakCanary: │ ~~~~~~~~~~~~~~~~~~
D/LeakCanary: ├─ kotlin.SynchronizedLazyImpl instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 230 B in 9 objects
D/LeakCanary: │ ↓ SynchronizedLazyImpl._value
D/LeakCanary: │ ~~~~~~
D/LeakCanary: ╰→ androidx.lifecycle.SavedStateHandlesVM instance
D/LeakCanary: Leaking: YES (ObjectWatcher was watching this because androidx.lifecycle.SavedStateHandlesVM received
D/LeakCanary: ViewModel#onCleared() callback)
D/LeakCanary: Retaining 210 B in 8 objects
D/LeakCanary: key = 375b335d-00db-4565-8c6d-0848ea7ca599
D/LeakCanary: watchDurationMillis = 5485
D/LeakCanary: retainedDurationMillis = 483
D/LeakCanary:D/LeakCanary: 15324 bytes retained by leaking objects
D/LeakCanary: Signature: 3074046c89ba82b393e6e7ba1f02c8a330683dbd
D/LeakCanary: ┬───
D/LeakCanary: │ GC Root: Input or output parameters in native code
D/LeakCanary: │
D/LeakCanary: ├─ dalvik.system.PathClassLoader instance
D/LeakCanary: │ Leaking: NO (SnapshotKt↓ is not leaking and A ClassLoader is never leaking)
D/LeakCanary: │ ↓ ClassLoader.runtimeInternalObjects
D/LeakCanary: ├─ java.lang.Object[] array
D/LeakCanary: │ Leaking: NO (SnapshotKt↓ is not leaking)
D/LeakCanary: │ ↓ Object[6667]
D/LeakCanary: ├─ androidx.compose.runtime.snapshots.SnapshotKt class
D/LeakCanary: │ Leaking: NO (Recomposer↓ is not leaking and a class is never leaking)
D/LeakCanary: │ ↓ static SnapshotKt.applyObservers
D/LeakCanary: ├─ java.util.ArrayList instance
D/LeakCanary: │ Leaking: NO (Recomposer↓ is not leaking)
D/LeakCanary: │ ↓ ArrayList[0]
D/LeakCanary: ├─ androidx.compose.runtime.Recomposer$recompositionRunner$2$unregisterApplyObserver$1 instance
D/LeakCanary: │ Leaking: NO (Recomposer↓ is not leaking)
D/LeakCanary: │ Anonymous subclass of kotlin.jvm.internal.Lambda
D/LeakCanary: │ ↓ Recomposer$recompositionRunner$2$unregisterApplyObserver$1.this$0
D/LeakCanary: ├─ androidx.compose.runtime.Recomposer instance
D/LeakCanary: │ Leaking: NO (CompositionImpl↓ is not leaking and Recomposer is in state Idle)
D/LeakCanary: │ ↓ Recomposer.knownCompositions
D/LeakCanary: ├─ java.util.ArrayList instance
D/LeakCanary: │ Leaking: NO (CompositionImpl↓ is not leaking)
D/LeakCanary: │ ↓ ArrayList[0]
D/LeakCanary: ├─ androidx.compose.runtime.CompositionImpl instance
D/LeakCanary: │ Leaking: NO (Composition not disposed)
D/LeakCanary: │ ↓ CompositionImpl.parent
D/LeakCanary: │ ~~~~~~
D/LeakCanary: ├─ androidx.compose.runtime.ComposerImpl$CompositionContextImpl instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 190 B in 6 objects
D/LeakCanary: │ ↓ ComposerImpl$CompositionContextImpl.this$0
D/LeakCanary: │ ~~~~~~
D/LeakCanary: ├─ androidx.compose.runtime.ComposerImpl instance
D/LeakCanary: │ Leaking: UNKNOWN
D/LeakCanary: │ Retaining 17.2 kB in 54 objects
D/LeakCanary: │ ↓ ComposerImpl.composition
D/LeakCanary: │ ~~~~~~~~~~~
D/LeakCanary: ├─ androidx.compose.runtime.CompositionImpl instance
D/LeakCanary: │ Leaking: YES (Composition disposed)
D/LeakCanary: │ Retaining 15.3 kB in 388 objects
D/LeakCanary: │ ↓ CompositionImpl.observations
D/LeakCanary: ├─ androidx.compose.runtime.collection.IdentityScopeMap instance
D/LeakCanary: │ Leaking: YES (CompositionImpl↑ is leaking)
D/LeakCanary: │ Retaining 13.2 kB in 356 objects
D/LeakCanary: │ ↓ IdentityScopeMap.scopeSets
D/LeakCanary: ├─ androidx.compose.runtime.collection.IdentityArraySet[] array
D/LeakCanary: │ Leaking: YES (CompositionImpl↑ is leaking)
D/LeakCanary: │ Retaining 10.5 kB in 252 objects
D/LeakCanary: │ ↓ IdentityArraySet[4]
D/LeakCanary: ├─ androidx.compose.runtime.collection.IdentityArraySet instance
D/LeakCanary: │ Leaking: YES (CompositionImpl↑ is leaking)
D/LeakCanary: │ Retaining 148 B in 5 objects
D/LeakCanary: │ ↓ IdentityArraySet.values
D/LeakCanary: ├─ java.lang.Object[] array
D/LeakCanary: │ Leaking: YES (CompositionImpl↑ is leaking)
D/LeakCanary: │ Retaining 132 B in 4 objects
D/LeakCanary: │ ↓ Object[0]
D/LeakCanary: ├─ androidx.compose.runtime.RecomposeScopeImpl instance
D/LeakCanary: │ Leaking: YES (CompositionImpl↑ is leaking)
D/LeakCanary: │ Retaining 68 B in 3 objects
D/LeakCanary: │ ↓ RecomposeScopeImpl.block
D/LeakCanary: ├─ androidx.compose.ui.platform.ComposeView$Content$1 instance
D/LeakCanary: │ Leaking: YES (CompositionImpl↑ is leaking)
D/LeakCanary: │ Retaining 20 B in 1 objects
D/LeakCanary: │ Anonymous subclass of kotlin.jvm.internal.Lambda
D/LeakCanary: │ ↓ ComposeView$Content$1.$tmp1_rcvr
D/LeakCanary: ╰→ androidx.compose.ui.platform.ComposeView instance
D/LeakCanary: Leaking: YES (ObjectWatcher was watching this because dev.yashgarg.qbit.ui.torrent.tabs.TorrentFilesFragment
D/LeakCanary: received Fragment#onDestroyView() callback (references to its views should be cleared to prevent leaks))
D/LeakCanary: Retaining 2.4 kB in 39 objects
D/LeakCanary: key = d15cfab8-cfee-4de6-82f2-9e5e4d4f6d02
D/LeakCanary: watchDurationMillis = 5489
D/LeakCanary: retainedDurationMillis = 488
D/LeakCanary: View not part of a window view hierarchy
D/LeakCanary: View.mAttachInfo is null (view detached)
D/LeakCanary: View.mID = R.id.filesComposeView
D/LeakCanary: View.mWindowAttachCount = 1
D/LeakCanary: mContext instance of dev.yashgarg.qbit.MainActivity with mDestroyed = false
D/LeakCanary: ====================================
Hi I'm encountering memory leak of this library as well, do you need help fixing this issue?