expo: [expo-image] When many image is rendered RAM usage goes over 2000mb and app crashes

Minimal reproducible example

https://github.com/Miigaarino/expo-image-memory-issue

Summary

Example below is after rendering images on newly created application. To test:

  1. Clone the repo
  2. Start expo
  3. Go to tab two on app

https://github.com/expo/expo/assets/48021917/95e53d6f-1cac-4f84-b77d-092457b9c03d

Environment

expo-env-info 1.2.0 environment info:
    System:
      OS: macOS 14.0
      Shell: 5.9 - /bin/zsh
    Binaries:
      Node: 18.18.0 - /opt/homebrew/opt/node@18/bin/node
      npm: 9.8.1 - /opt/homebrew/opt/node@18/bin/npm
    Managers:
      CocoaPods: 1.12.1 - /opt/homebrew/lib/ruby/gems/3.1.0/bin/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 23.2, iOS 17.2, macOS 14.2, tvOS 17.2, watchOS 10.2
    IDEs:
      Android Studio: 2022.3 AI-223.8836.35.2231.10671973
      Xcode: 15.1/15C65 - /usr/bin/xcodebuild
    npmPackages:
      expo: ~50.0.4 => 50.0.4 
      expo-router: ~3.4.6 => 3.4.6 
      react: 18.2.0 => 18.2.0 
      react-dom: 18.2.0 => 18.2.0 
      react-native: 0.73.2 => 0.73.2 
      react-native-web: ~0.19.6 => 0.19.10 
    npmGlobalPackages:
      eas-cli: 5.2.0
      expo-cli: 6.3.10
    Expo Workflow: managed

About this issue

  • Original URL
  • State: open
  • Created 5 months ago
  • Reactions: 6
  • Comments: 19 (4 by maintainers)

Most upvoted comments

i spoke with @tsapeta about this and he went through the trouble of looking at the images to determine if they could be the cause, he found some that are extremely large and would cause this issue, eg: https://assets-us-01.kc-usercontent.com/6c08ae22-aaba-00c5-2884-7221a976fac0/16abfdeb-34a3-4f47-9764-b72409d9ea44/Innovation Experts.jpg - this is a 1.9mb image (reasonable) but its dimensions are 22433 × 6125 (not reasonable). i would suggest ensuring that you use appropriately sized images for the device.

we have a couple ideas to help here:

  • introduce a prop like dangerouslyRenderOversizedImages which could default to false in dev and then warn when image dimensions exceed something like the device width x 5 / device height x 5 (5 being an arbitrary number that i’ve selected as an example of a possible threshold for warning). you could then choose to enable this prop if you OK with the memory usage implications of this.
  • you could use the allowDownscaling which would increase memory consumption but likely not by as much, however it would be consistent rather than a spike

Any info on this issue so far?

No, this issue is being ignored for some reason…

Thanks to everyone who trying to help with this 😇 Thank you guys @brentvatne, @tsapeta i really appreciate it. Maybe I will find a lot of new stuff exploring this issue.

@GeorgeHop Would you be able to provide a simple reproducible example? It looks like your use case (and repro) might be different than the one provided in this issue.

Image is not that small but still it should be saved on the disc only once

In the provided example, the problem is that the exact same image (22433 × 6125) is downloaded at least three times from different URLs. The URL is the cache key, so they are basically stored on the disc and memory separately.

The overall Increased memory consumption with allowDownscaling={false} is expected and it shows that you’re definitely using too big images. Keep in mind that the memory needed for the device to render the image is not the same as the file size which is compressed. This really big image is about 2mb in compressed form, but uncompressed (bitmap) it’s about 420mb.

Besides using too big images, the problem in expo-image I do see here is the spike for a short period of time when the images are being downscaled.

It can be flatlist or flash list with 100+ items that use same images… If you will render many lists in horizontal scrollview with paging and each page will render 100 same images you will see significant drop in performance… Currently I don’t recommend to show images in lists using this lib. use simple react-native Image component. I tried many props described it the docs and nothing seems to resolve this issue.

@Miigaarino - you could use an image cdn to process the images and serve them if you don’t control the source. you could serve a device appropriate sized image and the user would not need to use as much data or memory. if each of those images averages to 500kb and you load 175 then that would be 87.5mb, you could reduce that significantly by serving an image tailored for the device. https://web.dev/articles/image-cdns

Any info on this issue so far?

No, this issue is being ignored for some reason…

So I sent mail to @brentvatne and here is his response:

hey george,

could you copy all of those images directly to the repository that you shared there so we can inspect them more easily?

best, brent

@Miigaarino can you do this?

@brentvatne can you help us please?

Any info on this issue so far?

Yeah, for some reason simple image from react-native has issues with prefetch on iOS for example. Waiting when expo will fix issue with RAM because it crashes the app in production 😑

Thx for the warning. Was looking at this since expo 50 broke react-native image for me. I guess I need to debug it more 😃