Entry-level smartphones run on limited hardware, and are often used in environments featuring slow connectivity and coarse locations. This guide outlines the various factors that impact app performance and stability that should be given critical consideration when doing performance testing for such devices, and the tools that can be used to investigate and optimize.
This guide targets app developers and reviewers who need to determine how well an app will run on a low-end Firefox OS device and which factors will prevent it from doing so. It is assumed that not everyone using this guide will have access to a low-end device.
Note: Guidelines don't help if you don't check your apps often during development in your desktop browser, Firefox OS simulator and eventually on an actual device (see Different ways to run Gaia). You might need to switch tools when testing against different versions of Firefox OS. Pick the most powerful tool available for your version.
This section discusses how to debug and optimize for memory constraints.
Firefox DevTools WebIDE Monitor (2.1+)
The new WebIDE Monitor displays live and interactive memory graphs for all processes running on a connected Firefox OS run time. The Monitor tool is under active development and currently only enabled in Nightly. it currently requires a Firefox OS device running 2.1 (it won't work with lower Firefox OS versions or a Firefox Simulator.) To access it, go to WebIDE, plug in your Firefox OS 2.1 device, make sure it is successfully connected, and choose the Runtime > Monitor option from the WebIDE main menu.
Watch for the average memory that your app uses, and unexpected spikes. You will see the graph falling when garbage collection kicks in. Note that there is also some interaction between processes, as some memory is shared.
Firewatch is the WebIDE Monitor tool's predecessor — a node-based command-line tool that can be used to view a live memory graph for connected Firefox OS devices (versions supported up to 1.4.) It can also capture performance profiles and fetch about:memory details. Follow the instructions on the GitHub page to get it installed and running.
Watching the memory is low-impact so keep the tool running as you test your app. You can use it in the same way as the WebIDE Monitor.
On-device Developer HUD (1.4+)
The Developer Hud is an on-device developer tool that landed in Firefox OS 1.4. It shows various performance and platform details in real time, overlaid on the device display. Most importantly for our current use case, it can show currently used App memory, split up into various categories: JS objects, JS strings, JS other, DOM, Style and Other.
Always keep it running during testing to get a sense of overall memory use. Knowing the base memory, you will be able to confirm when you successfully reduced memory or regressed when applying optimizations. You will be able to see instantly which interactions decrease or increase memory usage.
The most basic tool to snapshot a memory report is available on Desktop Firefox at the URL
about:memory. A command-line tool enables the same report for Firefox OS.
Until the upcoming Memory Inspector tool lands in Firefox devtools, you can use Chrome’s Heap Profiler for getting memory usage information on desktop.
This section discusses the tools available for debugging high bandwidth usage.
Most developers track network requests with the Network Monitor. What it can also measure is how well your server caches static data (primed cache) and how heavy the initial payload is for the user (Empty cache). Considering that low-end phones will often only have EDGE available (150 KB/s in practice) keep the total requests size as small as possible. 1.5 MB on empty cache and 500 KB on primed cache are the recommended limits, but the lighter your app is, the better the user experience.
This section details some known device capabilities/limits that you should be mindful of when debugging low memory devices, and how to deal with those.
The internal storage limit for the Firefox profile, where the apps are stored, is around 80 Mb. To be considerate of that space, keep your packaged application size under 5 MB as a general rule.
The lowest RAM hardware configuration for Firefox OS is 128 MB, codename Tarako. Even on the more common 256 MB configuration, apps in the background are often cleaned up to recover memory. The Firefox OS Flame reference device can be configured from 1 GB down to 256 MB, to allow testing on different memory profiles.
Low-end Firefox OS devices don’t have A-GPS and therefore can only provide coarse geolocation data using wifi positioning. Your app should be OK when it only expects city accuracy, but if greater accuracy is desired, you might have to draw up a backup plan.
Spotty 2G connectivity makes data a premium and is prevalent in markets where low-memory devices are common. Optimize your app to work offline by storing data, minimizing server round trips and payloads and nicely falling back when requests fail. If your app needs to contact your server on regular basis for updates, use Firefox’s push notifications to schedule API requests as and when needed.
Memory usage best practices
When memory on the phone gets low, apps in the background will be “cleaned up”. This task-killer system is called Low-Memory-Killer (LMK) and the memory threshold triggers differ between phone version, configuration and app priority. An app in the foreground has higher priority and is only killed when memory gets dangerously low. To show its severity, this task-killer is called Out-Of-Memory (OOM) and will look like a crash to the user.
Note: To find out more about how memory management is handled in Firefox OS, read Out of memory management on Firefox OS.
To avoid task-killers marking your app, be considerate of memory use. Only take what you need while releasing what you can. Here are some good practices to follow.
Be responsive and get your images “tailored to fit”! Down sampling large images to fit will use excessive memory and should be avoided. Start with low-res images and serve higher resolutions when applicable.
Combine icons and images in CSS sprites to minimize the amount of image instances stored in memory. This also reduces bandwidth as only one well-compressed file needs to be sent over the air.
Images in <img> vs CSS
Minimize images defined in CSS to the ones needed for the layout and app design, as all images defined in CSS are loaded even when they are not used at the time. Use cases like emoticons in a messaging app are much easier on memory when using an
<img> element, which loads the image on demand and can be removed from memory when no longer needed.
Fonts are the preferred way for implementing application icons and even emoticons. Other options are CSS sprites and SVG, which all will use more memory and are less performant. Consider using font generators to customize the icon set to only contain what you actually use: downloading more font glyphs than you actually need is a waste of memory and bandwidth.
Discard or re-use elements
It is a common technique to keep elements in the DOM or memory for later use. Some sites keep the previous view of one-page apps stored somewhere, to be reuses when the user navigates back. Another memory hog is endless lists where a button in the end of a list allows you to load more elements that are appended to the existing ones. Hidden DOM elements often constitute the biggest memory usage on a page, especially when containing a lot of images.
Even though keeping pages in memory can make browsing faster, there needs to be a balance between gained performance and memory overhead. A good alternative to endless scrolling is simply pagination, replacing the old elements with a new list. Another more elaborate solution is to pool the list elements, e.g. recycling the old entries when loading new ones.
Storage vs memory cache
A common performance technique is loading data from client side databases like IndexedDB and then keeping it in memory so it can be rendered faster later on. This not only includes structured data but also templates, or localizations. Depending on the amount and complexity of the data this can take up substantial memory.
If memory is a concern, load the data when you need it and take the performance hit.
The Web Audio API is the recommended and more memory efficient way for implementing audio playback, especially for games. It allows you to manage the buffers you have loaded and added to the queue, giving fine-grained control over memory. The HTML5
<audio> element still has its use cases: streaming for example. Both specs can be combined to get the best of both worlds.