I'm experiencing some out of memory crashes in production. Trying to isolate the problem I could make a small app to reproduce the issue.
import React from 'react';
import { StyleSheet, Text, View, TouchableOpacity } from 'react-native';
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
render() {
const { count } = this.state;
const extraContent = new Array(200 * count).fill().map((_, index) => (
<View key={index}><Text>Line {index}</Text></View>
));
return (
<View style={styles.container}>
<View style={styles.actions}>
<TouchableOpacity onPress={() => this.setState({ count: count + 1})}>
<View style={styles.button}>
<Text style={styles.buttonText}>Add</Text>
</View>
</TouchableOpacity>
<TouchableOpacity onPress={() => count > 0 && this.setState({ count: count - 1})}>
<View style={styles.button}>
<Text style={styles.buttonText}>Remove</Text>
</View>
</TouchableOpacity>
</View>
<View>
<Text>Current count: {count}</Text>
<View>{extraContent}</View>
</View>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 50,
width: '100%',
},
actions: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-around',
},
buttonText: {
color: '#ffffff',
},
button: {
alignItems: 'center',
justifyContent: 'center',
backgroundColor: '#95afe5',
height: 50,
width: 100,
marginBottom: 5,
borderRadius: 5,
},
});
The code adds and removes some views from the screen when you press and or remove. It's expected that pressing Add
three times and then Remove
three times one would end with the same amount of memory use. What's really happening is that some of the memory is not released as shown in the graph:
It's interesting that adding again the three times and removing three times the peak of memory consumption is lower than the first round and there's no leak, but if we change to add/remove five times there's an extra pseudo leak.
I call it pseudo leak because from time to time, could understand why, a good portion of this retained memory is released, but it never comes back to the original baseline. It makes me believe that this effect may not be an actual leak, but some kind of cache instead.
In my production app this effect has reached 150+ MB leading to OOM crashes on devices with 1GB of RAM.
Does any one know what is it and if there's a way to avoid this behavior?