Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Image not releasing memory when dynamically changing source URI #21902

Closed
waqas19921 opened this issue Oct 23, 2018 · 7 comments
Closed

Image not releasing memory when dynamically changing source URI #21902

waqas19921 opened this issue Oct 23, 2018 · 7 comments
Labels
Bug Resolution: Locked This issue was locked by the bot.

Comments

@waqas19921
Copy link

waqas19921 commented Oct 23, 2018

Environment

React Native Environment Info:
    System:
      OS: macOS 10.14
      CPU: x64 Intel(R) Core(TM) i7-4770HQ CPU @ 2.20GHz
      Memory: 9.73 GB / 16.00 GB
      Shell: 3.2.57 - /bin/bash
    Binaries:
      Node: 8.12.0 - /usr/local/opt/node@8/bin/node
      Yarn: 1.9.4 - /usr/local/bin/yarn
      npm: 6.4.1 - /usr/local/opt/node@8/bin/npm
      Watchman: 4.9.0 - /usr/local/bin/watchman
    SDKs:
      iOS SDK:
        Platforms: iOS 12.0, macOS 10.14, tvOS 12.0, watchOS 5.0
    IDEs:
      Android Studio: 3.1 AI-173.4907809
      Xcode: 10.0/10A255 - /usr/bin/xcodebuild
    npmPackages:
      @storybook/react-native: ^3.4.11 => 3.4.11 
      react: 16.5.2 => 16.5.2 
      react-native: 0.57.2 => 0.57.2 
    npmGlobalPackages:
      react-native-cli: 2.0.1

Description

  • Image tag takes too much memory when i change its source on some button action.
  • I have to show and replace about 40 images in a single component.
  • After showing about 30 images app memory goes above 1GB
  • All images are just a few KBs in size
  • And Also it restarts phone upon testing on real Device
  • Placing images in javascript code have no issue in debug mode but crashes with excessive memory usage in production mode.
  • While placing images in iOS side with manual image references also produces excessive memory usage in dev mode.

Here is the memory screen shots:
screenshot 2018-10-23 at 8 21 49 am

Reproducible Demo

// Colors.js

const colors = {
  background: '#1F0808',
  clear: 'rgba(0,0,0,0)',
  facebook: '#3b5998',
  themeColor: '#3b5998',
  transparent: 'rgba(0,0,0,0)',
  silver: '#F7F7F7',
  steel: '#CCCCCC',
  error: 'rgba(200, 0, 0, 0.8)',
  ricePaper: 'rgba(255,255,255, 0.75)',
  frost: '#D8D8D8',
  cloud: 'rgba(200,200,200, 0.35)',
  windowTint: 'rgba(0, 0, 0, 0.4)',
  panther: '#161616',
  charcoal: '#595959',
  coal: '#2d2d2d',
  bloodOrange: '#fb5f26',
  snow: 'white',
  ember: 'rgba(164, 0, 48, 0.5)',
  fire: '#e73536',
  drawer: 'rgba(30, 30, 29, 0.95)',
  eggplant: '#251a34',
  border: '#483F53',
  banner: '#5F3E63',
  text: '#E0D7E5'
}

export default colors

\ Metrics.js

import {Dimensions, Platform} from 'react-native'

const { width, height } = Dimensions.get('window')

// Used via Metrics.baseMargin
const metrics = {
  marginHorizontal: 10,
  marginVertical: 10,
  section: 25,
  baseMargin: 10,
  doubleBaseMargin: 20,
  smallMargin: 5,
  doubleSection: 50,
  horizontalLineHeight: 1,
  screenWidth: width < height ? width : height,
  screenHeight: width < height ? height : width,
  navBarHeight: (Platform.OS === 'ios') ? 64 : 54,
  buttonRadius: 4,
  icons: {
    tiny: 15,
    small: 20,
    medium: 30,
    large: 45,
    xl: 50
  },
  images: {
    small: 20,
    medium: 40,
    large: 60,
    logo: 200
  }
}

export default metrics

\ ScreenStyles.js

import {StyleSheet} from 'react-native'
import {Metrics, Colors} from '../../Themes'

export default StyleSheet.create({
  container: {
    flex: 1,
    marginTop: Metrics.section
  },
  scrollContainer: {
    flex: 1,
    padding: Metrics.baseMargin
  },
  cardViewStyle: {
    flexWrap: 'wrap',
    marginVertical: Metrics.section
  },
  headerView: {
    flexWrap: 'wrap',
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between'
  },
  headerPhone: {
    flexWrap: 'nowrap',
    flexDirection: 'column',
    justifyContent: 'flex-start',
    backgroundColor: Colors.background
  },
  headerNameView: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    padding: Metrics.baseMargin,
    margin: Metrics.baseMargin
  },
  buttonsView: {
    flexWrap: 'wrap',
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    marginHorizontal: Metrics.baseMargin
  },
  headingText: {
    flex: 1,
    minHeight: 55,
    color: Colors.background,
    padding: Metrics.smallMargin
  },
  lockButton: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: Colors.themeColor,
    paddingVertical: Metrics.baseMargin - 1,
    paddingHorizontal: Metrics.baseMargin,
    marginLeft: Metrics.baseMargin
  },
  lockIcon: {
    color: Colors.snow
  },
  lockText: {
    color: 'white',
    paddingVertical: Metrics.smallMargin,
    paddingHorizontal: Metrics.smallMargin
  },
  arrowText: {
    color: Colors.background
  },
  audioIcon: {
    color: Colors.black
  },
  imageView: {
    alignItems: 'center',
    justifyContent: 'center'
  },
  image: {
    height: 150,
    width: 150,
    alignItems: 'center',
    justifyContent: 'center'
  },
  roundButtonsView: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    padding: Metrics.baseMargin,
    marginVertical: Metrics.doubleBaseMargin
  },
  circleButton: {
    height: 60,
    width: 60,
    borderRadius: 30,
    alignItems: 'center',
    justifyContent: 'center',
    backgroundColor: Colors.greenButton,
    marginHorizontal: Metrics.doubleBaseMargin
  },
  progressView: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'space-between',
    backgroundColor: Colors.transparent,
    padding: Metrics.baseMargin
  },
  otherView: {
    marginVertical: Metrics.doubleBaseMargin,
    padding: Metrics.doubleBaseMargin
  },
  inputView: {
    borderBottomWidth: 1,
    borderBottomColor: Colors.background,
    marginVertical: Metrics.doubleBaseMargin,
    marginHorizontal: Metrics.baseMargin
  },
  otherTextInputStyle: {
    flex: 1,
    height: 40
  },
  returnText: {
    flex: 1,
    textAlign: 'center',
    alignSelf: 'center',
    color: Colors.background,
    padding: Metrics.smallMargin
  }

})

// SelectionScreen.js

// @flow
import React, {Component} from 'react'
import Icon from 'react-native-vector-icons/MaterialIcons'
import {ScrollView, Text, View, TouchableOpacity, Dimensions, Image, TextInput} from 'react-native'

// Styles
import styles from './Styles/ScreenStyles'
import Metrics from '../Themes/Metrics'
import Colors from '../Themes/Colors'

let SYMPTOMS_ITEMS = [
  'fevers.jpg',
  'rigors.jpg',
  'fatigue.jpg',
  'weight_loss.jpg',
  'weight_gain.jpg',
  'swelling.jpg',
  'night_sweats.jpg',
  'headache.jpg',
  'dizziness.jpg',
  'neck_pain.jpg',
  'changes_vision.jpg',
  'hearing_loss.jpg',
  'ringing_ears.jpg',
  'swollen_glands.jpg',
  'painful_swallowing.jpg',
  'chest_pain.jpg',
  'cough.jpg',
  'sputum_production.jpg',
  'hemoptysis.jpg',
  'shortness_of_breath.jpg',
  'painful_breathing.jpg',
  'wheezing.jpg',
  'nausea.jpg',
  'vomiting.jpg',
  'loss_of_appetite.jpg',
  'bloating.jpg',
  'diarrhea.jpg',
  'jaundice.jpg',
  'confusion.jpg',
  'anxiety.jpg',
  'depression.jpg',
  'psychosis.jpg',
  'tingling_hands.jpg',
  'difficulty_sleeping.jpg',
  'muscle_aches.jpg',
  'joint_pain.jpg',
  'itching.jpg',
  'rash.jpg',
  'skin_dryness.jpg',
  'skin_changes.jpg',
  'hair_changes.jpg',
  'weakness.jpg',
  'seizure.jpg'
]

export default class SelectionScreen extends Component {
  constructor (props) {
    super(props)
    const {width} = Dimensions.get('window')
    this.state = {
      index: 0
    }
  }

  handleNextPress = () => {
    const {index} = this.state
    if (index < SYMPTOMS_ITEMS.length - 1) {
      this.setState({index: index + 1})
    }
  }

  handleBackPress =() => {
    const {index} = this.state
    this.setState({index: index - 1})
  }

  renderIconButton = (disable, icon, action, text) => {
    const style = [styles.lockButton, {backgroundColor: Colors.transparent}]
    return (
      <TouchableOpacity
        activeOpacity={0.8}
        style={style}
        disabled={disable}
        onPress={() => action()} >
        {text !== 'Next' && <Icon name={icon} size={20} color={Colors.blackText} />}
        <Text style={styles.arrowText}> {text.toUpperCase()}</Text>
        {text === 'Next' && <Icon name={icon} size={20} color={Colors.blackText} />}
      </TouchableOpacity>
    )
  }

  render () {
    const {index} = this.state

    return (
      <View style={styles.container}>
        <ScrollView style={styles.scrollContainer}>
          <View style={[styles.cardViewStyle]}>
            <View>

              <View style={styles.imageView}>
                <Image
                  source={{uri: SYMPTOMS_ITEMS[index]}}
                  style={styles.image} />
              </View>
            </View>
            <View style={styles.progressView}>
              {this.renderIconButton((index === 0), 'keyboard-arrow-left', this.handleBackPress, 'Back')}
              {this.renderIconButton(false, 'keyboard-arrow-right', this.handleNextPress, 'Next')}
            </View>
          </View>
        </ScrollView>
      </View>
    )
  }
}

Here above is the image tag used.

@react-native-bot
Copy link
Collaborator

Can you run react-native info and edit your issue to include these results under the Environment section?

If you believe this information is irrelevant to the reported issue, you may write [skip envinfo] under Environment to let us know.

@ignacioola
Copy link
Contributor

Duplicate of #12220, there's a good research on the issue there

@waqas19921
Copy link
Author

@ignacioola Sir you are referencing remote image, which is coming from some server.
I am loading from iOS bundled images.

@react-native-bot
Copy link
Collaborator

It looks like you are using an older version of React Native. Please update to the latest release, v0.57 and verify if the issue still exists.

The ":rewind:Old Version" label will be removed automatically once you edit your original post with the results of running react-native info on a project using the latest release.

@ignacioola
Copy link
Contributor

@waqas19921 in the reproduction code of #12220 you can see it's using local images. Maybe I am not seeing something else but it seems to be pretty close to your case.

@waqas19921
Copy link
Author

@ignacioola i have tried this solution before posting this issue but no success.

@dulmandakh
Copy link
Contributor

Hello there 👋 this issue has been reported for an old version of React Native. Ideally we'd like everyone to be using 0.59 (see the awesome changes it brought) but we know updating can be a pain. We are going to close this issue because it's from a version before 0.57, which is really old.

But please, if it's actually still an issue with 0.59 please comment below and we can reopen it. Even better, please send us a pull request with a fix 😊

@facebook facebook locked as resolved and limited conversation to collaborators Mar 19, 2020
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Mar 19, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Bug Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests

5 participants