JQuery memory leak problems and causes

What are some common problems or coding patterns in jQuery that cause a memory leak?




I saw a number of questions related to calling ajax () or removing jsonp or DOM in StackOverflow. Most memory leak problems in jQuery are focused on specific problems or browsers, and it would be nice to have a list of standard memory leak patterns in jQuery.

Here are some related questions about SO:

  • Why is jQuery so badly leaking memory?
  • Simple jQuery Ajax causes memory leak in Internet Explorer
  • Memory leak using jQuery Ajax queries

Online Resources:

+43
performance javascript jquery garbage-collection memory-leaks
Feb 18 '11 at 20:09
source share
2 answers

From what I understand, memory management in javascript is done by reference counting - as long as the reference to the object still exists, it will not be freed. This means that creating a memory leak in a single-page application is trivial and may disable usage functions coming from the java background. This does not apply to jQuery. Take the following code, for example:

function MyObject = function(){ var _this = this; this.count = 0; this.getAndIncrement = function(){ _this.count++; return _this.count; } } for(var i = 0; i < 10000; i++){ var obj = new MyObject(); obj.getAndIncrement(); } 

This will look fine until you look at memory usage. MyObject instances are never freed while the page is active, due to the "_this" pointer (increase the maximum value of i to see it more sharply). (In older versions of IE, they were never released before the program exited.) Since javascript objects can be split between frames (I do not recommend trying this because it is seriously temperamental), there are times when even in a modern javascript browser, objects can freeze much longer than they are intended.

In a jquery context, links are often kept to save the overhead of searching for dom - for example:

 function run(){ var domObjects = $(".myClass"); domObjects.click(function(){ domObjects.addClass(".myOtherClass"); }); } 

This code will be stored on domObject (and all its contents) forever, because of a link to it in the callback function.

If jquery authors skipped instances like this internally, then the library itself is leaking, but most often it is client code.

The second example can be fixed by explicitly clearing the pointer when it is no longer needed:

 function run(){ var domObjects = $(".myClass"); domObjects.click(function(){ if(domObjects){ domObjects.addClass(".myOtherClass"); domObjects = null; } }); } 

or search again:

 function run(){ $(".myClass").click(function(){ $(".myClass").addClass(".myOtherClass"); }); } 

A good rule of thumb is to be careful when defining your callback functions and avoiding too much nesting where possible.

Edit: as mentioned in Eric's comments, you can also use this pointer to avoid looking for unnecessary dom:

 function run(){ $(".myClass").click(function(){ $(this).addClass(".myOtherClass"); }); } 
+28
Mar 30 '11 at 12:35
source share

I will be contributing one anti-pattern here, which is a middle chain leak.

One of the strengths of jQuery is the chaining API, which allows you to continue to modify, filter, and manipulate elements:

 $(".message").addClass("unread").find(".author").addClass("noob"); 

At the end of this chain, you have a jQuery object with all the ".message.author" elements, but this object accesses the ".message" objects and returns to them. You can get them using the .end() method and do something with them:

  $(".message") .find(".author") .addClass("prolific") .end() .addClass("unread"); 

Now when using this path there are no problems with leaks. However, if you assign the result of a chain to a variable that has a long lifespan, backreferences to earlier sets are preserved and cannot be garbage collected until the variable goes beyond the bounds. If this variable is global, links never go beyond.

So, for example, let's say you read in one of your 2008 blog posts that $("a").find("b") was "more efficient" than $("ab") (although it’s not even worth it think about such micro-optimization). You decide that you need a global list of pages to host the authors list for you to do this:

 authors = $(".message").find(".author"); 

Now you have a jQuery object with a list of authors, but it also refers to a jQuery object, which is a complete list of posts. You will probably never use it or even know it there, and it takes up memory.

Note that leaks can only occur with methods that select new elements from an existing set, such as .find , .filter , .children , etc. Documents indicate when a new set is returned. Simply using the chain API does not leak if the chain has simple non-filtering methods like .css , so this is normal:

 authors = $(".message .author").addClass("prolific"); 
+15
May 16 '14 at 18:13
source share



All Articles