【问题标题】:React Native pseudo leaking memory after remove elements from screen (ios)从屏幕中删除元素后反应本机伪泄漏内存(ios)
【发布时间】:2019-03-05 06:23:47
【问题描述】:

我在生产中遇到了一些内存不足的崩溃。试图找出问题,我可以制作一个小应用程序来重现问题。

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,                                                                                                                                                                                   
  },                                                                                                                                                                                                   
});

当您按下和/或移除时,代码会在屏幕上添加和移除一些视图。预计按三下Add 然后按三下Remove 将以相同的内存使用量结束。实际情况是部分内存没有释放,如图所示:

有趣的是,再次添加3次删除3次内存消耗峰值低于第一轮并且没有泄漏,但是如果我们更改为添加/删除5次,则会出现额外的伪泄漏。

我称之为伪泄漏,因为有时,可以理解为什么,大部分保留的内存被释放,但它永远不会回到原始基线。这让我相信这种效果可能不是真正的泄漏,而是某种缓存。

在我的生产应用中,这种效果已达到 150+ MB,导致在具有 1GB RAM 的设备上发生 OOM 崩溃。

有谁知道它是什么以及是否有办法避免这种行为?

【问题讨论】:

    标签: react-native memory-leaks


    【解决方案1】:

    也许你的 onPress 道具隐含地返回了不必要的数据。如果您将 {} 放在箭头之后以防止返回,会发生什么情况。有什么区别吗?

    您也可以为您的 setState 做一些事情。考虑尝试:setState(() => {…code})

    这也可能会有所帮助: When to use React setState callback

    【讨论】:

      【解决方案2】:

      对不起,这更像是一个评论,但我想添加一些代码块来帮助交流。我认为您的示例通过每次在渲染函数中创建元素来击败一些 React 的缓存。如果extraContent 中的元素更稳定,结果会有什么不同吗?一种方法如下:

      render 之外创建extraContent,将其存储在状态中,并使remove 函数返回数组的一个切片。比如:

      // in constructor
      this.state = {
        extraContent: [],
      };
      
      // in component
      add() {
        const totalElements = this.state.extraContent.length;
        this.setState({ extraContent: this.state.extraContent.concat(new Array(200).fill().map((_, index) => (                                                                                                                             
            <View key={totalElements + index}><Text>Line {totalElements + index}</Text></View>                                                                                                                                               
          ))
        });
      }
      
      remove() {
        const totalElements = this.state.extraContent.length;
        if (totalElements > 0) {
          this.setState({ extraContent: this.state.extraContent.slice(0, totalElements - 200) });
        }
      }
      
      render() {
        // cut out everything before the return
        // use add and remove functions in your TouchableOpacity components
      }
      

      我之所以提到这一点,是因为您在示例中发现的问题可能与实际应用中的问题不同,除非您在其中使用相同的策略来创建组件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-09-16
        • 2020-03-05
        • 2022-01-13
        • 1970-01-01
        • 1970-01-01
        • 2013-04-10
        • 2021-01-25
        相关资源
        最近更新 更多