Massive memory leak with array values
Description
We use reanimated for graph charts, which requires us to use array values in reanimated shared values. When doing this memory is allocated but when the component un-mounts, this memory is not cleared.
Expected behavior
The memory is cleared when component un-mounts and shared values are not used anymore
Actual behavior & steps to reproduce
- Use a profiler to monitor memory usage of the app, in release mode
- Create a component that uses arrays in reanimated shared values
- un-mount this component
- watch the memory not being cleared
- mount & unmount this component until the app gets killed by the OS
Snack or minimal code example
Full minimal reproducible code here: https://github.com/Anybowdy/reanimated-leaks-example
Just need un-mount & remount a component like this multiple times:
export const AnimatedScreen: FC<Props> = ({ onPress }) => {
const { goBack } = useNavigation();
const largeArray = Array.from(Array(100000).keys());
useSharedValue(largeArray);
useSharedValue(largeArray);
useSharedValue(largeArray);
return (
<View style={{ flex: 1, alignItems: "center", justifyContent: "center" }}>
<StyledButton text="Navigate back" onPress={() => goBack()} />
</View>
);
};
Package versions
| name | version |
|---|---|
| react-native | 0.68.2 |
| react-native-reanimated | 2.8.0 |
Affected platforms
- [ ] Android (not tested on android)
- [x] iOS
- [ ] Web
Video
We are experiencing the exact same issue, would be nice if this was fixed. Could it be related to #2824 ?
same issue here, I'm sure the memory leak occured in reaniamated's native thread, is there any plan to fix that?
Something that can be a viable fix in some situations in the meantime is to move the shared values lower in the component tree. In the array of values solution it might look like this:
function Component({arrayOfItems}) {
const sharedValueArray = useSharedValue(arrayOfItems.map(e=>0));
return (
<View>
{arrayOfItems.map(e=>{
return (
<Animated.View
{/* do something with shared value */}
/>
)
}
</View>
)
}
Instead we can move the Animated.View into its own component like:
function ChildComponent({item}) {
const animatedValue = useSharedValue(0);
// ... rest of component
}
Then in the parent
function Component({arrayOfItems}) {
return (
<View>
{arrayOfItems.map(e=>{
return (
<ChildComponent/>
)
}
</View>
)
}
This can support a variable number of child components and avoid the memory leak since we're not creating any arrays. If you actually need to use the shared value in the parent you'd be kind of screwed though b/c you couldn't easily do the above without some really janky solution
Thanks for the suggestion @iway1-hstk ! However in our case we don't have the choice, we need array in our shared values to compute coordinates on a chart, like here:
Any updates on this? Seems like a pretty big problem.
Hey! π
The issue doesn't seem to contain a minimal reproduction.
Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?
Is this happening in older versions? I will test older ones to figure out when it broke (if it's not a long term issue)
Edit: confirmed across all versions to be an issue
I have found a hacky fix, albeit not great, but it works. Strings have no problems with memory leaks, so I can confirm that if you stringify the data and then parse it when in use, it works perfectly for me for well over 5000 values so far. I'm very sure that will work great for the line graphs mentioned above.
notes.value = JSON.stringify(longArray);
useDerivedValue(() => {
const notesValue = JSON.parse(note.value) as Notes[];
// do something with it, it doesn't leak
});
Hey @eric-edouard @marksyzm @Arjan-Zuidema @richardo2016x!
Just wanted to let you know that the whole core of shared values in Reanimated was basically rewritten in #3722 and released in 3.0.0-rc.8. Can you please check if this solves your issues?
Thanks @tomekzaw - I'm planning to run it through my app over Christmas to test it out
Hey @eric-edouard @marksyzm @Arjan-Zuidema @richardo2016x!
Just wanted to let you know that the whole core of shared values in Reanimated was basically rewritten in #3722 and released in 3.0.0-rc.8. Can you please check if this solves your issues?
Thanks @tomekzaw , it's nice of you to notify us! I will try the new rc release after my work this period and let you know if it works.
Hey @richardo2016x, did you test how rewritten shared values works with array?
@Rag0n I can confirm that this issue is fixed at 3.0.0-rc10.
Hey @richardo2016x, did you test how rewritten shared values works with array?
Sorry for replying late, I am so busy the past time. We haven't upgraded react-native-reanimated to 3.0.0 due to other limitations of our biz. But I'm glad to see @lhreska mentioned they have confirmed it has been fixed in their application. π
Any updates on this issue ?? This has been on the radar for over three years and, sadly, there is no definitive solution yet. The user feedback about these crashes is growing, and it's become a real pain point.
is there a solution for this or a reliable workaround ? Thanks for your attention to this matter.
"react-native-screens": "^3.22.0",
"@react-navigation/bottom-tabs": "^6.3.2",
"@react-navigation/drawer": "^6.4.4",
"@react-navigation/native": "^6.0.11",
"@react-navigation/native-stack": "^6.7.0",
"react-native-reanimated": "^3.3.0",
"react-native-gesture-handler": "^2.12.0",
Solutions attempted so far without success:
- enableScreens(false)
- super.onCreate(null);
Logcat
β¬βββ
β 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 (InternalLeakCanaryβ is not leaking and A ClassLoader is never
β leaking)
β β ClassLoader.runtimeInternalObjects
ββ java.lang.Object[] array
β Leaking: NO (InternalLeakCanaryβ is not leaking)
β β Object[2191]
ββ leakcanary.internal.InternalLeakCanary class
β Leaking: NO (MainActivityβ is not leaking and a class is never leaking)
β β static InternalLeakCanary.resumedActivity
ββ com.appname.MainActivity instance
β Leaking: NO (Activity#mDestroyed is false)
β mApplication instance of com.appname.MainApplication
β mBase instance of androidx.appcompat.view.ContextThemeWrapper
β β AppCompatActivity.mDelegate
β ~~~
ββ androidx.appcompat.app.AppCompatDelegateImpl instance
β Leaking: UNKNOWN
β Retaining 1.0 kB in 16 objects
β mAppCompatCallback instance of com.appname.MainActivity with
β mDestroyed = false
β mContext instance of com.appname.MainActivity with mDestroyed = false
β mHost instance of com.appname.MainActivity with mDestroyed = false
β β AppCompatDelegateImpl.mActionBar
β ~~~~
ββ androidx.appcompat.app.ToolbarActionBar instance
β Leaking: UNKNOWN
β Retaining 552.4 kB in 2395 objects
β β ToolbarActionBar.mDecorToolbar
β ~~~~~
ββ androidx.appcompat.widget.ToolbarWidgetWrapper instance
β Leaking: UNKNOWN
β Retaining 552.4 kB in 2391 objects
β β ToolbarWidgetWrapper.mToolbar
β ~~~~
ββ com.swmansion.rnscreens.ScreenStackHeaderConfig$DebugMenuToolbar instance
β Leaking: UNKNOWN
β Retaining 552.2 kB in 2387 objects
β View not part of a window view hierarchy
β View.mAttachInfo is null (view detached)
β View.mWindowAttachCount = 1
β mPopupContext instance of com.facebook.react.uimanager.ThemedReactContext,
β wrapping activity com.appname.MainActivity with mDestroyed = false
β mContext instance of com.facebook.react.uimanager.ThemedReactContext,
β wrapping activity com.appname.MainActivity with mDestroyed = false
β β CustomToolbar.config
β ~~
ββ com.swmansion.rnscreens.ScreenStackHeaderConfig instance
β Leaking: UNKNOWN
β Retaining 2.0 kB in 14 objects
β View not part of a window view hierarchy
β View.mAttachInfo is null (view detached)
β View.mID = R.id.null
β View.mWindowAttachCount = 1
β mContext instance of com.facebook.react.uimanager.ThemedReactContext,
β wrapping activity com.appname.MainActivity with mDestroyed = false
β β View.mParent
β ~~~
ββ com.swmansion.rnscreens.Screen instance
β Leaking: UNKNOWN
β Retaining 511.8 kB in 1829 objects
β View not part of a window view hierarchy
β View.mAttachInfo is null (view detached)
β View.mID = R.id.null
β View.mWindowAttachCount = 1
β mContext instance of com.facebook.react.uimanager.ThemedReactContext,
β wrapping activity com.appname.MainActivity with mDestroyed = false
β β Screen.fragment
β ~~~~
β°β com.swmansion.rnscreens.ScreenStackFragment instance
β Leaking: YES (ObjectWatcher was watching this because com.swmansion.
β rnscreens.ScreenStackFragment received Fragment#onDestroy() callback and
β Fragment#mFragmentManager is null)
β Retaining 2.1 kB in 72 objects
β key = b116c7d1-e55c-4a42-9170-eca82ba9dd7d
β watchDurationMillis = 7292
β retainedDurationMillis = 2249
METADATA
Build.VERSION.SDK_INT: 28
Build.MANUFACTURER: HUAWEI
LeakCanary version: 2.11
App process name: appname
Class
Logcat 2
βββ
β GC Root: Global variable in native code
β
ββ com.swmansion.reanimated.NativeProxy instance
β Leaking: UNKNOWN
β Retaining 221 B in 8 objects
β β NativeProxyCommon.mNodesManager
β ~~~~~
ββ com.swmansion.reanimated.NodesManager instance
β Leaking: UNKNOWN
β Retaining 9.4 kB in 318 objects
β mContext instance of com.facebook.react.bridge.ReactApplicationContext,
β wrapping com.appname.MainApplication
β mReactApplicationContext instance of com.facebook.react.bridge.
β ReactApplicationContext, wrapping com.appname.MainApplication
β β NodesManager.mAnimationManager
β ~~~~~~~
ββ com.swmansion.reanimated.layoutReanimation.AnimationsManager instance
β Leaking: UNKNOWN
β Retaining 794 B in 24 objects
β mContext instance of com.facebook.react.bridge.ReactApplicationContext,
β wrapping com.appname.MainApplication
β β AnimationsManager.mReanimatedNativeHierarchyManager
β ~~~~~~~~~~~
ββ com.swmansion.reanimated.layoutReanimation.ReanimatedNativeHierarchyManager
β instance
β Leaking: UNKNOWN
β Retaining 942.6 kB in 6901 objects
β β NativeViewHierarchyManager.mTagsToViews
β ~~~~
ββ android.util.SparseArray instance
β Leaking: UNKNOWN
β Retaining 929.7 kB in 6881 objects
β β SparseArray.mValues
β ~~~
ββ java.lang.Object[] array
β Leaking: UNKNOWN
β Retaining 923.6 kB in 6879 objects
β β Object[217]
β ~~~
ββ com.swmansion.rnscreens.Screen instance
β Leaking: UNKNOWN
β Retaining 2.2 kB in 17 objects
β View not part of a window view hierarchy
β View.mAttachInfo is null (view detached)
β View.mID = R.id.null
β View.mWindowAttachCount = 5
β mContext instance of com.facebook.react.uimanager.ThemedReactContext,
β wrapping activity com.appname.MainActivity with mDestroyed = false
β β View.mParent
β ~~~
β°β com.swmansion.rnscreens.ScreenStackFragment$ScreensCoordinatorLayout instance
β Leaking: YES (ObjectWatcher was watching this because com.swmansion.
β rnscreens.ScreenStackFragment received Fragment#onDestroyView() callback
β (references to its views should be cleared to prevent leaks))
β Retaining 3.7 kB in 72 objects
β key = 8b340022-4f6e-4653-a6c8-ad5639e3ff8e
β watchDurationMillis = 5828
β retainedDurationMillis = 827
β View not part of a window view hierarchy
β View.mAttachInfo is null (view detached)
β View.mWindowAttachCount = 1
β mContext instance of com.appname.MainActivity with mDestroyed = false
METADATA
Build.VERSION.SDK_INT: 28
Build.MANUFACTURER: HUAWEI
LeakCanary version: 2.11
App process name:appname
Class count: 18907
Instance count: 266551
Primitive array count: 172560
Object array count: 29962
Thread count: 57
Heap total bytes: 26966868
Bitmap count: 75
Bitmap total bytes: 14020308
Large bitmap count: 0
Large bitmap total bytes: 0
Db 1: open /data/user/0/appnamer/databases/RKStorage
Db 2: open /data/user/0/com.appname/databases/com.
google.android.datatransport.events
Db 3: open /data/user/0/com.appname/no_backup/androidx.work.workdb
Stats: LruCache[maxSize=3000,hits=84650,misses=180148,hitRate=31%]
RandomAccess[bytes=9194085,reads=180148,travel=66525003196,range=33782477,size=4
0598308]
Analysis duration: 15559 ms
A fresh repo with memory leak on Android https://github.com/Ahmed-Imam/memoryLeak
This is still an issue both on iOS and Android
Hey! π
The issue doesn't seem to contain a minimal reproduction.
Could you provide a snack or a link to a GitHub repository under your username that reproduces the problem?
Problem is resolved since version 3+
Yes verified, it is fixed, THanks
Do we have any patch for lower versions @piaskowyk