Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Do javascript closures with a this/self reference cause memory leaks?

From what I understand about memory leaks, referencing an out-of-scope var within a closure will cause a memory leak.

But it is also a common practice to create a "that" var in order to preserve the "this" reference and use it within a closure, especially for events.

So, what's the deal with doing stuff like this:

SomeObject.prototype.createImage = function(){
    var that = this,
        someImage = new Image();
    someImage.src = 'someImage.png';
    someImage.onload = function(){
        that.callbackImage(this);
    }
};

Wouldn't that add a little leakage to a project?

like image 961
George Hess Avatar asked Feb 17 '12 00:02

George Hess


3 Answers

Yes, yes it does cause memory leaks, at least in some browsers (guess which). This is one of the more compelling reasons to put your trust in one of the various frameworks available and to set up all your event handlers via its mechanisms instead of directly adding "DOM 0" event handlers like that.

Internet Explorer (at least prior to 9, and possibly including 9) has two memory allocation mechanisms (at least) internally: one for the DOM, and one for JavaScript (well JScript). They don't understand each other. Thus even if a DOM node is freed up, any closure memory as in your example will not be freed.

edit — Oh, and the reason I mention frameworks is that they generally include code to try and mitigate this problem. The avoidance of attaching anything to DOM node properties is one of the safest approaches. All browsers worth worrying about (including ancient IE versions) have alternative ways of attaching event handlers to DOM nodes, for example.

like image 134
Pointy Avatar answered Oct 20 '22 04:10

Pointy


Shot in the dark here, but I reckon that:

someImage.onload = function(){
    that.callbackImage(this);
    someImage.onload = null
}

would clean up the "memory leak" left by that

like image 40
Eric Avatar answered Oct 20 '22 05:10

Eric


There was a time with IE that circular references involving DOM elements (which were typically formed by closures when assigning a function to a listener) caused memory leaks, e.g.

function foo() {
  var someEl = document.getElementById('...');
  someEl.onclick = function() {...};
}

However, I think they are fixed or patched sufficiently that unless testing shows otherwise, they can be ignored. There are also a number of ways to avoid such closures, so even if they are an issue, they can be worked around (e.g. don't create circular references involving DOM elements).

Edit

Using libraries or any other method of attaching listeners can still create circular references and memory leaks, e.g. in IE:

function foo() {
  var el = document.getElementById('d0');

  // Create circular reference through closure to el
  el.attachEvent('onclick', function(){bar(el);});

}

function bar(o) {
  alert(o == window.event.srcElement);  // true
}

window.onload = foo;

The above uses attachEvent to add a listener (which pretty much all frameworks will use for IE < 9, including jQuery) yet still creates a circular reference involving a DOM element and so will leak in certain versions of IE. So just using a library will not fix the issue, you need to understand the causes and avoid them.

like image 1
RobG Avatar answered Oct 20 '22 05:10

RobG