viromedia / viro

ViroReact: AR and VR using React Native
MIT License
2.31k stars 483 forks source link

Crash when navigating between Scene on Android. Memory leak ? #749

Open beauvaisbruno opened 5 years ago

beauvaisbruno commented 5 years ago

Environment

Please provide the following information about your environment:

  1. Development OS: Windows,
  2. Device OS & Version: Android 9
  3. Version: ViroReact 2.16.0, React Native 0.59.3
  4. Device(s): Huawei P20 EML-L09

Description

Great thank you for your library. It is a great job. We are building a City Quest where users are navigating between 10 scenes. There is a lot of 3D assets (~100 Mo in total). I could reproduce the problem with a very simple project (see code below).

On android, the app crash when navigating between scene (from 5 to 10 times) using the replace method. The crash is similar on debug and release variant. I suspect a memory leak (see profiler screenshot) : the heap is always growing when a new scene is displayed. It seems the previous scene is still retaining memory.

Reproducible Demo

Complete reproducible demo https://github.com/beauvaisbruno/virobugs/tree/scene-navigation

import {AppRegistry, View} from 'react-native';
import {Viro3DObject, ViroAmbientLight, ViroARScene, ViroARSceneNavigator} from "react-viro";
import React from "react";

const SceneOne = ({sceneNavigator}) => {
  return <ViroARScene>
    <ViroAmbientLight color={"#aaaaaa"}/>
    <Viro3DObject
      source={require("./res/heavy0.glb")}
      type="GLB"
      position={[0, 0, -2]}
    />
    <Viro3DObject
      source={require("./res/clickable0.glb")}
      type="GLB"
      position={[0, 0, -1]}
      onClick={() => {
        sceneNavigator.replace({scene: SceneTwo});
      }}
    />
  </ViroARScene>;
};
const SceneTwo = ({sceneNavigator}) => {
  return <ViroARScene>
    <ViroAmbientLight color={"#aaaaaa"}/>
    <Viro3DObject
      source={require("./res/heavy1.glb")}
      type="GLB"
      position={[0, 0, -2]}
    />
    <Viro3DObject
      source={require("./res/clickable1.glb")}
      type="GLB"
      position={[0, 0, -1]}
      onClick={() => {
        sceneNavigator.replace({scene: SceneOne});
      }}
    />
  </ViroARScene>;
};

const Navigator = () => {
  return <View style={{flex: 1}}><ViroARSceneNavigator
    initialScene={{scene: SceneOne}}
    apiKey={"SOME_API_KEY"}/>
  </View>;
};

AppRegistry.registerComponent('virobugs', () => Navigator);

profile

res.zip debugLogcat.log debugErrorOnlyLogcat.log

Turtleted21 commented 5 years ago

we have the same problem with galaxy tab S5e

beauvaisbruno commented 5 years ago

I could reproduce the crash with a 7Mo asset. After ~40 loading the app crash. profile7mo 7MoAsset.zip

beauvaisbruno commented 5 years ago

You can avoid crash if you unmount then remount ViroARSceneNavigator. But you lost your origin and the transition is not as smooth as using the ViroARSceneNavigator navigation functions.

import {AppRegistry, View} from 'react-native';
import {Viro3DObject, ViroAmbientLight, ViroARScene, ViroARSceneNavigator} from "react-viro";
import React, {useState} from "react";

const SceneOne = (props) => {
  return <ViroARScene>
    <ViroAmbientLight color={"#aaaaaa"}/>
    <Viro3DObject
      source={require("./res/heavy40Mo1.glb")}
      type="GLB"
      position={[0, 0, -2]}
    />
    <Viro3DObject
      source={require("./res/clickable1.glb")}
      type="GLB"
      position={[0, 0, -1]}
      onClick={() => {
        props.navToScene(SceneTwo);
      }}
    />
  </ViroARScene>;
}

const SceneTwo = (props) => {
  return <ViroARScene>
    <ViroAmbientLight color={"#aaaaaa"}/>
    <Viro3DObject
      source={require("./res/heavy40Mo2.glb")}
      type="GLB"
      position={[0, 0, -2]}
    />
    <Viro3DObject
      source={require("./res/clickable2.glb")}
      type="GLB"
      position={[0, 0, -1]}
      onClick={() => {
        props.navToScene(SceneOne);
      }}
    />
  </ViroARScene>;
}

const Navigator = () => {
  const [scene, setScene] = useState({current:SceneOne});
  const navToScene = (newScene) => {
    setScene(null);
    const clear = setTimeout(() => {
      setScene({current:newScene});
      clearTimeout(clear);
    }, 1);
  }
  if (!scene)
    return null;
  return <View style={{flex: 1}}>
    <ViroARSceneNavigator
      initialScene={{
        scene:scene.current, passProps: {navToScene}
      }}
      apiKey={"SOME_API_KEY"}/>
  </View>;
};

AppRegistry.registerComponent('project', () => Navigator);