Skip to content

Terminated due to memory issue #407

@yahya-valus

Description

@yahya-valus

📝 Description

I am building a React Native application that uses ViroReact for an Augmented Reality (AR) coin collection feature. The core AR view is wrapped in a within a child component (Viro.tsx/ObjectDetectionAR). This component is conditionally rendered in the parent component (App.tsx) based on a state variable (isNearby), which simulates a WebSocket response indicating proximity to a coin.

The issue is that every time the AR view is unmounted and then re-mounted (i.e., isNearby changes from truthy to falsy and back), memory consumption increases by approximately 200MB on iOS (observed via Xcode Memory Debugger). After 10-12 such state changes/re-renders, the memory usage reaches around 2GB, and the OS terminates the app.

This strongly suggests that the underlying native ViroARSceneNavigator view is not being completely destroyed or cleaned up when its React Native component unmounts, leading to a cumulative memory leak.

💻 Environment

React Native version: 0.81.1

ViroReact version: 2.44.2

Target Platform: iOS and Android

Development OS: MacOS 26.1 (25B78)

🔄 Reproduction

  • Parent Component (App.tsx)
import Viro from './Viro';
import React, { useMemo } from 'react';
import { SafeAreaView } from 'react-native-safe-area-context';
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';

function App() {
  const [showAR, setShowAR] = React.useState<boolean>(false);

  const ViroComp = useMemo(() => {
    return <Viro />;
  }, []);

  return (
    <SafeAreaView style={styles.container} edges={['top']}>
      {showAR ? (
        ViroComp
      ) : (
        <View style={styles.innerContainer}>
          <Text style={styles.text}>
            Other Component Will be displayed here
          </Text>
        </View>
      )}

      <TouchableOpacity
        style={styles.button}
        onPress={() => setShowAR(!showAR)}
      >
        <Text style={styles.text}>Toggle AR</Text>
      </TouchableOpacity>
    </SafeAreaView>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
  },
  innerContainer: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  text: {
    fontSize: 30,
    width: '80%',
    color: 'black',
    fontFamily: 'Arial',
    textAlign: 'center',
    textAlignVertical: 'center',
  },
  button: {
    height: 80,
    width: '100%',
    alignItems: 'center',
    backgroundColor: 'teal',
    justifyContent: 'center',
  },
});

export default App;
  • Child Component (Viro.tsx)
import {
  ViroARScene,
  ViroARSceneNavigator,
  ViroText,
  ViroTrackingReason,
  ViroTrackingStateConstants,
} from '@reactvision/react-viro';
import React, { useState } from 'react';
import { StyleSheet } from 'react-native';

const HelloWorldSceneAR = () => {
  const [text, setText] = useState('Initializing AR...');

  function onInitialized(state: any, reason: ViroTrackingReason) {
    console.log('onInitialized', state, reason);
    if (state === ViroTrackingStateConstants.TRACKING_NORMAL) {
      setText('Hello World!');
    } else if (state === ViroTrackingStateConstants.TRACKING_UNAVAILABLE) {
      console.log('Tracking Unavailable');
    }
  }

  return (
    <ViroARScene onTrackingUpdated={onInitialized}>
      <ViroText
        text={text}
        scale={[0.5, 0.5, 0.5]}
        position={[0, 0, -1]}
        style={styles.helloWorldTextStyle}
      />
    </ViroARScene>
  );
};

export default () => {
  return (
    <ViroARSceneNavigator
      autofocus={true}
      initialScene={{
        scene: HelloWorldSceneAR,
      }}
      style={styles.f1}
    />
  );
};

var styles = StyleSheet.create({
  f1: { flex: 1 },
  helloWorldTextStyle: {
    fontFamily: 'Arial',
    fontSize: 30,
    color: '#ffffff',
    textAlignVertical: 'center',
    textAlign: 'center',
  },
});
  • Steps to Reproduce

    1. Launch the application.
    2. Open Xcode and monitor the memory usage for the application process.
    3. Click the "Show AR" button to set isNearby to true, mounting the . Observe memory spike (~200MB).
    4. Click the "Hide AR" button to set isNearby to false, unmounting the . Observe memory drop, but the baseline remains elevated.
    5. Repeat steps 3 and 4 approximately 10-12 times.
    6. The app will be killed by the OS due to excessive memory usage.

💡 Expected Behavior

When the component is unmounted (i.e., isNearby becomes false), all associated native resources and memory (including the AR session, camera feed, and Viro framework state) should be completely released, and the baseline memory usage should return to its initial state.

❓ Potential Cause

The issue is likely that the native VRTARSceneNavigator view is not being properly deallocated, or its underlying ARSession is not being paused/destroyed, when the React Native component's lifecycle componentWillUnmount (or equivalent in functional components) is triggered.

Any guidance or potential workarounds to force the destruction of the native AR session upon unmount would be greatly appreciated.

Metadata

Metadata

Assignees

No one assigned

    Labels

    to be releasedIt's fixed/done and coming in a next update

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions