Flutter Web for Progressive Web Mobile SDKs has always been a good challenge for us to solve at Nuclei.
As we moved to production, we started facing Out of Memory Issues in android while loading Flutter Web inside a web-view, in some of the android devices.
The logs as you see, do not have much of information to trace the root cause for the same.
The root cause of the OOM issues can be:
- Memory leaks
- The RAM consumed by the graphics component used to render bitmaps, image caching, scrolling or animations, etc. by flutter web while drawing them to canvaskit.
How did we mitigate the same ?
Firstly, Fix all the memory leaks found in Leak Canary while running the web build embedded in android native sample app. Checked if WebViewActivity is not leaked by ensuring that no WebViewActivity is alive when flutter web build is not running. Made sure that Activity Stack in native android is cleared, on the app back press and device back press of the WebViewActivity.
Secondly, We profiled our build attaching android memory profiler in order to get the above data, and noticed the points of actual memory raise. We could find that the GC easily frees up the java/native objects as and when required, but the graphics component part takes more time to release. And when the user is ruthless with UI or does fast scrolling or jumps from one module to other fast enough, then the GC finds it difficult to pace up with the user. As a solution to this, we ran the GC manually, every time before you do a new API request or open a new module. This ensures that enough memory is ready before the graphics resource is rendered.
In android this can be done using System.gc() , although the garbage collector is supposed to behave automatically in its standard ways, but using this is a safe-keeper from OOM issues.
Thirdly, we addressed heavy widgets like Shimmer effect and Cached Network Image. We removed shimmer totally and added the 3 dot loader. Also, we optimised the cache for Cached Network Image, by fixing minCacheWidth and minCacheHeight based on device pixel ratio, so that it caches images based on the device pixel ratio, and not the actual size.
Testing Observations Then and Now
Earlier when we opened a flutter web category Eg: Category A — the initial memory spike due to graphics weight was around 150–200mb 🤧, now it has reduced to 80–90 mb 😎. When we opened Category B and then Category A and forth, this memory was never freed by the GC(Garbage collector) and hence consuming upto 2 gigs 🤯 sometimes, pretty obvious leading to OOM. Now it is not more than 400 to 500mb 😎. Switching back and forth now, always frees up enough memory for the launching module.
An observation from Android memory profiler while running flights and bus, before (1) and after (2) the fixes.
- RAM consumption upto 2 Gigs
- RAM consumption reduced to 400 to 500 mb — which is standard. If you have 4gb RAM phone then nearly 12% of your RAM. If you have 8gb RAM phone then nearly 6% of your RAM.
This problem was indeed a pain point for us. But finally we have conquered it, thereby making our solutions for Flutter Web in order to building SaaS products more inclusive and reliable day by day. 😄