They say Marc Andreessen, co-founder of Netscape and co-author of the Mosaic browser, once said:
[An operating system] is just a bag of drivers.
People have been fantasizing about the web as application platform for as long as we’ve had it. Nearly a decade later, we’re really just getting started at realizing this vision–of truly reproducing the power of traditional operating system APIs inside of the browsers.
While some have had this vision of browser-as-application-runtime since the beginning, most of us have traditionally viewed the browser as a web page renderer. It’s only been in the past few years that some have begun to push hard on changing this status quo. Google stands out in this group both with the creation of boundary-pushing “desktop-quality” applications like Gmail and in describing Google Chrome as an application run-time, not a page viewer. [1]
Here in the Mozilla Developer Tools Lab, we’ve been pondering the various gaps in the tool-chain when you treat the browser as a serious, OS-grade application run-time. We’ll talk more about the landscape of tools and what’s available in a different post. In this one, we’d like to talk about one of the gaps we’ve found: memory tools.
The Memory Problem
It’s a rare application developer indeed who doesn’t wish their GUI to be “snappy”. In technical terms, Jakob Nielsen defines snappy as responding to user input within a tenth of a second. To put that in perspective, that’s shorter than it takes the average person to blink their eye.
If an application’s appetite for memory crosses over into gluttony, it can put a developer’s snappiness ambitions at risk. There are at least a couple of reasons why.
First, applications have a finite amount of memory available to them. When the operating system runs out of memory, a cool trick lets them supplement disk space for memory, but when this happens, performance hits the floor–hard drives, being mechanical, are orders of magnitude slower than memory.
While web applications don’t directly interact with the operating system to obtain memory, the browser does both for its own internal functions and as a proxy to the appetite of the web applications it is displaying, and as a web application’s memory consumption grows, so does that of the browser.
Therefore, if an individual web application’s memory needs grow sufficiently large, it can force the operating system to start dipping into disk space to provide sufficient memory, and when this happens, kiss any semblance of responsiveness goodbye.
Since there’s no way for a web application to know how much memory is available before this performance doomsday occurs, its good behavior to make your memory footprint as svelte as possible.
Garbage Collection and You
But there’s another, much more important reason why small web application memory footprints are good. It has to do with the way memory is handled in a browser. Like Java and pretty much any scripting language, JavaScript manages memory allocation for developers. This frees developers from having to deal with the tedious bookkeeping associated with manual memory management, but it comes at a cost.
That cost is embodied by the garbage collector. As a web application executes, it is constantly creating new objects, most of which are fairly transient–they are part of a transaction that has completed, like creating some short-lived jQuery objects to look-up some DOM elements. These objects consume memory. Eventually, the web application has created enough objects and is therefore consuming enough memory that the collector needs to wade through all the objects to see which ones are no longer being used and therefore represent memory that can be released.
This is where the performance implication comes in. To do its work, the collector stops the web application’s execution. Typically, this happens so fast that the user doesn’t notice. But when a web application creates lots and lots of objects, and these objects aren’t transient, the collector has a lot of work to do–it must go through all of these objects to ferret out the ones that are no longer used. This is turn results in delays that the user can perceive–and impairs the application’s responsiveness.
Leaks
To be clear, most web pages and web applications don’t push the browser’s memory limitations enough to cause performance problems related to either of the scenarios above. As stated at the outset, this blog entry is about those web applications that need to treat the browser as a high-performance run-time, which in the context of this entry means that they have much-larger-than-average memory requirements.
However, these issues apply to more than just those web apps that are designed to use large amounts of memory; they can also apply to long-running applications which, over time, gradually consume small amounts of memory until the footprint grows to be quite large. When an application consumes more memory than its designers intended, it is said to leak memory. [2]
And this leads in turn to a third way in which memory can give the shift to performance: when the browser itself leaks memory. It turns out that mere mortals have created web browsers, and every so often they’ve made mistakes which can trigger either of the two scenarios described above.
Diagnosing the Problem
So how do you as a developer go about troubleshooting these sorts of problems? Today, there’s really only one way good way to do it: use the operating system’s tools. Unfortunately, this option doesn’t provide the right level of detail; you can either see how much memory the browser is consuming in aggregate (which is fine to let you know that your memory use is increasing, but doesn’t tell you why) or you can see which data structures in the browser itself are consuming the memory (which is fine if understand the guts of the browser, but it’s pretty hard for anyone else to understand how this maps into the web application they’ve developed).
What’s missing is a tool targeted at web developers that makes it easy to understand what’s happening with their application’s memory usage. We propose to create such a tool.
Start Small, Start Focused
Our plan is to start small and address two key needs that are presently unmet by any of the existing, developer-friendly, easy-to-use tools we’ve seen on any browser. These needs are:
- Understand the memory usage of an application
- Understand the garbage collector’s behavior
While here in the Developer Tools Lab we’re most interested in creating developer tools for the entire web community (i.e., not just Firefox users), in this case because the tool will need some pretty deep integration with the browser, we’re going to start with Firefox (because we sit close to the engineers who work on it).
We plan on the initial implementation of this tool to be simple. For memory usage, we want to introduce the ability to visualize the current set of non-collectible JavaScript objects at any point in time (i.e., the heap) and give you the ability to understand why those objects aren’t collectible (i.e., trace any object to a GC root). For the garbage collector, we want to give you a way to understand when a collection starts and when it finishes and thus understand how long it took.
Help Us!
This is obviously a small step into a large world. Is it a good first step? What do you think we should do differently? We’d love to hear from you, and thanks for reading!
[1] Of course, Firefox does a fine job of acting as application run-time; my point is that Google was the first to call out web applications as a distinct class of web content and to talk in terms of supporting these for their mainstream browser. Incidentally, Mozilla Labs’ Prism project sought to pioneer this idea years before.
[2] I’m using the term “leak” in a much more general way than is common in most developer communities. Traditionally, the term is applied to an application that allocates memory and then neglects to deallocate it when done. Because a language like JavaScript doesn’t allow developers to manually allocate or deallocate memory, it is impossible to leak at the JS level in this sense. But in my broader sense, any time a developer unintentionally creates memory footprint (e.g., by continuously storing objects in a hash in a mis-designed cache, etc.), I consider it a leak. This broader definition is borrowed from the Java community.
[3] Image of Marc Andreessen taken from http://images.businessweek.com/ss/08/05/0520_valleyboys/source/4.htm
[4] Image of the Google Chrome comic book taken from http://www.google.com/googlebooks/chrome/
[5] Image of Jakob Nielsen taken from http://www.useit.com/
NOTE: I cross-posted this to my blog; please use the comment thread over there.
Richard wrote on :