Entry-level smartphones run on limited hardware, and are often used in environments featuring slow connectivity and coarse location acquisition. This guide outlines the various factors that impact app performance and stability that should be given critical consideration when 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's assumed that not everyone using this guide will have access to a low-end device.
Note: Guidelines help only if you check your apps often during development in your desktop browser, Firefox OS simulator and eventually on a 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's successfully connected, and on the WebIDE main menu click Runtime then Monitor.
Watch for the average memory that your app uses, and unexpected spikes. You'll 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 current App memory use, split up into various categories: JS objects, JS strings, JS other, DOM, Style and Other.
Keep it running during testing to get a sense of overall memory use. Knowing the base memory, you'll be able to confirm when you have successfully reduced memory or regressed when applying optimizations. You'll be able to see instantly which interactions decrease or increase memory use.
The most basic tool for obtaining a snapshot memory report is the URL
about:memory, available on Desktop Firefox. A command-line tool enables the same report for Firefox OS.
Until the Memory Inspector tool lands in Firefox devtools, you can use Chrome’s Heap Profiler to get memory use information on the desktop.
This section discusses the tools available for debugging high bandwidth use.
Most developers track network requests with the Network Monitor. It can also measure 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, a general rule is to keep your packaged application size under 5 MB.
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 against different memory profiles.
Low-end Firefox OS devices don’t have A-GPS and therefore can only provide coarse geolocation data using Wi-Fi positioning. If your app only expects city level accuracy it should be OK. If greater accuracy is desired alternative positioning options may need to be considered.
In markets where low-memory devices are common, erratic 2G connectivity is common making data services unreliable. 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 use 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.