At the inaugural WebPerfDays, Loreena Lee of the Gmail Client Performance Team gave a great talk on using the new Profiles feature of Chrome Developer Tools to make Gmail faster. In their hunt to find performance issues within the Gmail client interface, her team ran into the limitations of their current toolset. By collaborating with the Chrome team, the profile tool made quite a few improvements. Lee pointed out a few misconceptions about memory and performance. In this age of abundant memory, there is a belief that more memory automatically improves the performance of an application. The Gmail team found that this does not hold true in all cases. By collecting data from the thousands of Google employees using Gmail themselves, Lee and her team found that as the memory footprint grew, so did the client-side latency. They also discovered that as the process size got bigger, the garbage collector struggled to function. Memory leaks were found to be the biggest drain on client-side performance. So what’s the biggest culprit in memory leaks in Gmail? Event listeners, or more specifically
unlisten() to an event from Google’s Closure Library events.js. The team also found many missing
dispose() for events that created listeners from disposable.js. The greater message for both of these issues is that the garbage collector does not always clean up properly in all cases. In fact, there were instances where up to 25% of the garbage was not collected. So for long-running apps, like Gmail, it is imperative to use tools like the profiler to identify these issues which will only show themselves over time.
Finding Memory Bloat
You can see the memory usage grow as I used the application for the first 5 minutes, and you’ll also see some normal garbage collection happening as I move to different portions of the application. To see if there were any memory leaks, I let the application idle for 5 more minutes. The memory footprint grew during the second half of the test, but garbage collected itself. What didn’t happen, and what shows some memory issues, is that the total footprint never fell below the lowest points around the 5 minute mark. Memory allocations made during the app usage in the first 5 minutes were never garbage collected even though I had moved to an entirely different portion of the site.
Identifying the Culprit
Now that there appears to be a memory issue somewhere, we have to hunt down where it is coming from. This is where we can take advantage of the Profiles by taking snapshots of the head before and after the suspected bloat. I took a snapshot of the application after it had fully loaded but before taking any actions, I took a second snapshot after I had walked through the same steps from the timeline view above (the footprint had grown by 60%). Using the comparison view, I can see there were 1,587
<div> elements created and only 34 deleted. Drilling down, I can see that the vast majority of the elements are detached from the DOM.