Skip to content

Memory Leaks when component is disposed  #702

@Shaw-Signaturize

Description

@Shaw-Signaturize

Environment

System:
OS: macOS 13.2.1
CPU: (8) x64 Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
Memory: 16.34 MB / 16.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 16.17.1 - ~/.nvm/versions/node/v16.17.1/bin/node
Yarn: 1.17.3 - /usr/local/bin/yarn
npm: 8.15.0 - ~/.nvm/versions/node/v16.17.1/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
Managers:
CocoaPods: 1.11.2 - /usr/local/bin/pod
SDKs:
iOS SDK:
Platforms: DriverKit 22.2, iOS 16.2, macOS 13.1, tvOS 16.1, watchOS 9.1
Android SDK: Not Found
IDEs:
Android Studio: 3.4 AI-183.6156.11.34.5522156
Xcode: 14.2/14C18 - /usr/bin/xcodebuild
Languages:
Java: Not Found
npmPackages:
@react-native-community/cli: Not Found
react: 18.2.0 => 18.2.0
react-native: 0.71.3 => 0.71.3
react-native-macos: Not Found
npmGlobalPackages:
react-native: Not Found

Description

When using pager view with larger resources, memory seems to leak by the amount contained in the active page.
Originally discovered in a project using a routing library but for this example the toggle component simulates a page disposal.
As resources are proportionally small for the example to reproduce press the toggle button multiple times
Although the leaking memory from this example is small It has been able to reach over 8gb where images have client side processing applied such as grayscale.

Memory Profile with pager view included
image

Memory Profile with pager view excluded

image

Reproducible Demo

import React, { useMemo, useState, useCallback } from 'react';
import { 
  View, 
  Button,
  StyleSheet, 
  SafeAreaView, 
} from 'react-native';

import FastImage from 'react-native-fast-image'

import PagerView from 'react-native-pager-view';

const data = new Array(100).fill(1)

function App() {
  const [visible, setVisible] = useState(true)

  const onPress = useCallback(() => {
    setVisible((x) => !x)
  }, [])

  return (
    <SafeAreaView style={{ flex: 1}}>
      <View style={{ flex: 0 }}>
        <Button title={'Toggle'} onPress={onPress} />
      </View>
      <Toggle visible={visible}>
        <Pager />
      </Toggle>
    </SafeAreaView>
  );
};

function Toggle({ visible, children }) {
  return visible
    ? children
    : null
}

function Pager() {  
  const content = useMemo(() => {
    return data.map((x, i) => {
      return <Image value={i} key={i} />
    })
  }, [data])

  return (
    // Apply comment to the below line to demo memory is stable without this component
    <PagerView style={styles.pagerView} initialPage={0}>
      <View key="1">
        {content}
      </View>
    </PagerView>
  )
}

function Image({ value }) {
  const source = useMemo(() => {
    const i = value % 40
    return { uri: `https://unsplash.it/1200/1200?image=${i}` }
  }, [value])

  return (
    <FastImage
      style={styles.image}
      source={source}
      resizeMode={FastImage.resizeMode.cover}
    />
  )
}

const styles = StyleSheet.create({
  pagerView: {
    flex: 1,
  },
  image: {
    margin: 8,
    aspectRatio: 1,
    width: 400,
    height: 400
  }
});

export default App

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions