Tab shutdown and onUnload spinloop

August 26, 2009

We have a bug that tabs sometimes can take too long to close, where (as generally in Chrome-land) "too long" is defined as "more than instantly".

The common culprit in slow tab shutdown is onUnload handlers. These allow pages to do something as they're being shut down (more on what that exactly means later). We can only start the handler after the user has indicated it's time to close the tab, so pretty much any time they take is too much. If we're especially unlucky it can take a rather long time, as running the page JS requires potentially swapping back in the tab process.

One performance improvement that was done in this area was to track, for each tab, whether the page JavaScript registers an onUnload handler at all; if it doesn't, we can just kill the tab process immediately rather than doing the IPCs to tell the page JS to run.

Another tweak was to change the "tab is hung, do you want to kill it?" monitor to be much more aggressive when we're in the process of shutting down a tab. Ojan tells me we have it at a second. But that doesn't help you when you click a link — the onUnload handler still runs, but we can't put the hang checker in aggressive shutdown mode.

The interesting meta-question is: why does this API even exist? I asked some JavaScript hacker friends and they had two broad reasons. One, you use it to clean up memory leaks in IE (IE can't GC circular references between JS and the DOM, so you break the reference cycles when "shutting down"). But in general, they explained, the more common application is from people who don't know better.

Because when you're shutting down, any asynchronous operation you begin isn't guaranteed to complete (pinging a server to release a lock, for example — Google Docs does (did?) this). The browser cancels all your outstanding requests when your page is killed, so there's a race between your onUnload ping going out and the page getting cancelled.

Which takes us back to the original bug. I heard today that some ad networks, which (I imagine) want to track "how long" a user was on the page, also ran into this shutdown racing problem. Their "fix": start the ping, then run a JS loop that spins for half a second or so, blocking shutdown. From their perspective, as soon as their handler returns, the page may shut down, so the only way to keep their page up long enough for the ping to go through is to spin.

Worse, some pages have multiple ads from the same network! Comment 64 on the bug mentions one where three separate ads that each serially spin for 200ms on shutdown. Sadly, this affects all browsers and sucks for everyone. Probably the proper fix is to work with browser vendors on a better API (see also the disasterous <a ping=...> discussion, which is almost exactly the same problem, but politically unpopular with users who don't understand the consequences).