Save 99% CPU memory by optimizing images in your Flutter app! Prevent crashes.

Samyak Jain
CommandDash
Published in
3 min readApr 26, 2022

While developing applications of all scale and types, adding images to Flutter has always been simple. Depending upon if we want to use an asset, network or a cached image, we add it like below. Correct?

What if we tell you that this way of adding images is severely unoptimised, can quickly block a huge chunk of CPU memory and can very easily make your app crash!

Yes, for instance that you have a network image of resolution 2200 X 1800 with a size of approx 8MB. However in your application, you only wish to display a thumbnail version of it in a constrainedBox of height and width as 100px. The orignal image dimensions are unnecessarily large for our requirements here.

The way Flutter Image Renderer works is that it caches the image with full resolution in memory and blocks up the complete 8MB of image size space. Imagine displaying a list of 300 such images and the total memory adds up to 2.4GB which is enough to crash your app on iOS 15 which has a memory heap limit of 2098MBs only.

This happened to us in a production music streaming application which inspired us to fully optimize the image rendering.

How did we optimize this?

The issue even though very critical, fortunately has a simple fix. We basically have to tell the image rendered how much resolution is required for any image that fits within the particular widget.

First Step: debugInvertOversizedImages = true

In your top level MaterialApp widget, add the tag debugInvertOversizedImages = true in the build function.

This function interestingly tell us which images are significantly oversized in comparison to size of the widget by

  1. Flipping them horizontally and inverting its color

Example: An unoptimzed splash screen

2. Showing an error in the debug console.

Console log for the above splash image warning

Now that we are aware of all unoptimized app images, let’s get to fixing them.

Step 2: cacheWidth and cacheHeight

These two params can be passed two any of the image widgets informing them the required size of the image resolution. So for example, a responsive widget that can take up size of 200 X 150 in its maximum state, suitable cache params shall be passed. The flutter rendered then only cache the particular resolution of the image no matter what the orignal size was.

Results:

Upon testing before and after cases on a Pixel 4A, significant memory optimization (>99%) was observed in our real production app saving our users from janked frames and crashes.

Before Optimizing: Allocated = 3.0GB

The following scenario when run on iPhone 13 (iOS15), crashes the app.

After Optimizing: Allocated = 20MB

Running smoothly on both android and iOS devices. 🙌

Mission Accomplished 🚀

--

--

Samyak Jain
CommandDash

Engineering @CommandDash | World's First IDE Agents Marketplace