Thursday, May 10, 2012

Memory leaks in JavaScript: What are they, how to spot them, how to create them


I've just been helping out with some interviews for a new developer and JavaScript is a major part of my role and the role we're recruiting for. To be honest the candidate wasn't that good and he didn't really understand JavaScript however in the interview he confused JavaScript with C# and started to discuss memory leaks in JS. I wanted to intervene however it was at that point I realised how little I know about memory leaks in JS apart from the fact they use up lots of memory and slow things down.



When thinking about it during the interview the only thing I can remember is OReilly's Def Guide (think it was the fourth edition) mentioning Mark and Sweep Garbage Collections. But that has been fading ever since I read that and I can't really expand on that. I've found very little on this subject that's clear and concise (apart from an article by Crockford by that wasn’t that clear).



Can someone please sum up as simply as possible: What are memory leaks in JS, how we can spot them, how to create them - I've been writing JS for years and this has totally knocked my knowledge and confidence as I've never really thought about it!


Source: Tips4all

3 comments:

  1. Actually, a "true" memory leak should never be possible in a language that has an automatic garbage collector. So if there is a memory leak, its always an error in the underlaying engine (for instance, the problem of named function expressions in some IE's).

    So, after we clarified that, it is still possible to gain a lot of memory with javascript and hold it without releasing. But that is not a true memory leak anyway. For instance, each function call creates a closure in ECMAscript. A lexical closure does, among other things, copy a reference to each parent context's data (activation and variable objects). So this needs some memory, especially if you're creating a lot of closures.

    Another example from the Javascript DOM world: We are creating a dynamic image using new Image() and set the source to a big image. Now, we have a reference to the image and it cannot get garbage collected until all references are gone or unused (even if a good memory tool will correctly tell you that the memory was used for images and not for javascript).

    But actually these are the only scenarios where you really can "leak" memory in this language. Again, it's not really leaking memory like a C malloc() where you forget to free() that section again. Since there is no dynamic memory managment in ECMAscript this stuff is totally out of your range.

    ReplyDelete
  2. var trolls = (function () {
    var reallyBigObject = eatMemory();

    // make closure (#1)
    // store reallyBigObject in closure
    (function () {
    var lulz = reallyBigObject;
    })();

    // make another closure (#2)
    return function () {
    return 42;
    };
    })();


    You would expect trolls to just be function () { return 42; } and you would expect the reallyBigObject to be removed and garbage collected.

    It's not, because if a single closure (#1) references a variable in the outer scope. Then all closures (#2 aswell) reference that variable.

    Just because you have a reference to #2 means you have a reference to reallyBigObject which won't be cleared until #2 is dead.

    Now consider your average closure heavy architecture where you wrap everything in closures and nest them 10 deep. You can see how easy it is to hold references to objects.

    Note the above details apply to v8. Any fully ES5 compliant browser would leak with

    var trolls = (function () {
    var reallyBigObject = eatMemory();
    return function () {};
    })();


    Because every inner function must have a reference to every closure variable defined in the outer scope, as per ES5. Most browsers take shortcuts and optimize this in a way that is not noticable.

    ReplyDelete
  3. Javascript is implemented different through all browsers. But there is a standard which all browsers should follow: ECMAscript.

    Consider that all modern languages implement its own versions of reference counting, so the best way to avoid memory leaks is referencing all unused variables to null.

    ReplyDelete