JS gps ability for tracking memleaks

2012-08-07

So we're working on a big environment. The whole thing is a huge app with complex code paths, pubsub mechanisms, and accessors that make debugging very hard. But we have a memory leak. And I was asked to find it, good luck. Turns out, tooling has taken a step back when it comes down to finding memory leaks...

The past


In IE there used to be tools for this. This by itself was no surprise because IE was notorious for creating "unfixable" memory leaks with closures, and of course because IE was very popular at the time. Tools like sIEve and drip were invaluable to hunt down those bugs. And they worked good!

The current


The days of crappy browsers are behind us though. At least for desktop ;) And thus, tools like sIEve cease to exist. Which is terrible because memory leaks are still a problem! Especially with the growing size and complexity of js based apps these days. Even more because those apps live longer in a session than they used to. So for them, memory leaks are still a big problem. Many coders are unaware that memory is retained in closures and is not released until the last link is released. But if you keep a site like twitter open all the time and it leaks memory every time it polls the server for updates, you'll run out of memory pretty quickly.

And even the bestest of programmers can cause these leaks. The simple ones are easy to catch but there are so many ways to cause a leak, it's not even funny. We seem to have caused a leak with fetching a resource. That's about as far as I came with Chrome dev tools anyways. After that I managed to create a small test case with a setTimeout that would repetitively load (and release) a resource using that mechanism. Chrome's about:memory clearly showed that it leaked memory. The page grew from some 40mb to 2g in matter of minutes. Oops.

Chrome


So Chrome has many tools. The "Profiles" tab allows you to take snapshots of the current heap. That's great. Except that it's utter crap. Sure, you get some kind of structure that probably represents all the memory currently being retained by your application. However, you get this in the form of an unnavigable tree with stuff like (code deopt data)[] @164079. I'm sure that's handy if you have Chrome in a (real) debugger and you can jump to these addresses in the RAM... for us (web) developers it's completely meaningless.

The only other tool for memory leaks Chrome offers is the about:memory page. This shows how much RAM each open tab is retaining. Not very helpful with finding the source of a memory leak, but at least you can use it to zoom in on one. If the app is gaining memory when it shouldn't, you've got a problem.

Now sIEve (or was it drip) allowed you an automatic up to date view of resources being retained. More importantly, it could show you a diff of retained resources between a certain time-frame. It could tell you leaks between refreshes. Etc. I want to see which elements have been created and are not being released. I'm not interested in the internals, I want to see relevant stuff for js. Stuff I can grasp. Meh.

And yes, firebug (Firefox) has a similar function. And I'm sure Dragonfly (Opera) does too. But they were out of my reach in this case.

GPS tracker


Now what would be nice is if there was a tool where you could create a special "tracking object" and pass that around. Then at any point, the tool would tell me which elements are retaining that tracker. Or if none do, tell me that is has been released. The "location" of the tracker can be the variable (file and line number) that's currently holding a structure (simple object path) that contains this tracker. For any retained reference of it.

I'm actually wondering whether it'd be possible to achieve such a thing with rewriting the source. Every variable can be found and wrapped in some code that checks it. Then any object structure can be completely walked (with es5's Object.getOwnPropertyNames) to search all structures exhaustively. Time doesn't matter here, we just want to know where it is, if it's still retained. This will give you a clue where your memory leak might be. Just put such a tracker in an object you think should be destroyed over time.

Rewriting would be something like this:

Code:
var foo = {};
function f(){}
foo = f;
f = console.gps('xxx');

// transforms to something like

var foo = {};
register('/foo', foo);
function f(){}
register('/f', f);
foo = f;
register('/foo', foo);
f = console.log('xxx');
register('/f', f);

Where register would be a function that logs the current value of any variable in the system. The first parameter is an Xpath kind of system of uniquely referencing variables and structures in source code. I dubbed this JSpath for myself. The second parameter is the current value. So at any time you could ask for the location of some GPS object. The code would search through it and tell you the JSpath of all structures that contain it.

Code:
var foo = {x: [1, 2, console.gps('xxx')], y:"hi", z:console.gps('yyy')};
console.track('xxx'); // => /foo{x[3]}
console.track('yyy'); // => /foo{y}

(The actual format of the JSpath would be a bit more complex, but you get the idea...)

Of course rewriting as I'm talking about here would never destroy such variables. So it'd never actually be destroyed (in fact, the whole app would become one huge memory leak...). But while researching on 32g ram dev machines, that shouldn't be a big problem :)

Of course, it would be awesome if these tools could be supplied natively by a browser vendor. You couldn't do it in js itself because you would need a weakmap kind of thing to detect the release of a resource. And it has been ruled out that weakmaps can detect whether a "weak key" is released or not due to security concerns. Ohwell...

So, icanhaz gps object tracking in js please?