user1084440
user1084440

Reputation: 51

Memory leaks with closures and (jQuery) DOM events in current browsers?

I'm new to javascript and seem to be having a bit of problem tracking down a memory leak. I've narrowed it down to a section that seems to cause the memory leak, since the code is fairly complex. I'll post a different example that trivializes it but causes the same problem (just much smaller).

Code Example

Basically, I have some code that dynamically builds HTML and attaches events to the HTML. The HTML gets rebuild with every AJAX request. This all works fine and dandy the first time but after each AJAX request the browser memory goes up(not always equal)! This problem can be reproduced by clicking run multiple times on jsfiddle and watching the browsers memory. My assumption is that the closures that get created are never garbage collected but I'm not sure? If that is the case is there a better way to do this without closures that won't cause any problems?

This happens in FF8, latest version of Chrome, and IE 8. Most likely all others - just what I've tested.

I've put some comments in the code that should help.

Thanks!

EDIT: Ok, so after doing some more research using sIEve, I can see that the number of DOM nodes is doubling on every AJAX call. I've updated the example to simulate this. So my question is why aren't the DOM elements garbage collected after calling jQuery empty or remove functions? I've also looped through the elements in stuff unbinding the event handlers and setting each DOM element js reference to null with no impact...

Code Example

Upvotes: 3

Views: 1283

Answers (5)

Jonathan Rich
Jonathan Rich

Reputation: 1738

This has to do with the DOM's GC and the JavaScript GC not being friends. The basic gist is that if something is referenced by the DOM, the JS GC might not destroy it, and vice versa. This idea might be outdated, as it comes up in Crockford's book which is a few generations of browser old.

I see a few potential problems here, which might be specific to the JS Fiddle but might not be:

  • Is it necessary to assign F?
  • You're creating a LOT of DOM elements here one at a time,
  • You're re-creating F at each run, so the issue is more likely in the DOM's GC than JavaScript's GC
  • JavaScript's GC is a mark-and-sweep scanner, which means it's "lazy." You can see this in your script - if you run it ten times, the memory usage spikes up very high, but eventually the abandoned objects get garbage collected and the memory usage goes down.
  • The closure you have to worry about is the one assigned to the click element, but you aren't using a closure here.

But I don't see any real problems, and after a few minutes my memory usage goes back down to normal.

In short, you don't have a memory leak (at least a pressing one), your JS interpreter's GC is just being lazy. You're abandoning a lot of DOM elements, which isn't good, and is the reason your memory is spiking, but that is a short-term performance hit, not a long-term page load issue.

Upvotes: 3

Cᴏʀʏ
Cᴏʀʏ

Reputation: 107536

I'm with ShaggyFrog on this one. You can decrease the memory allocation by removing local variables and emptying that appendUs array manually when you're done with it. In Chrome, I saw the memory allocation jumping up by 800KB - 1MB on every run of your script. Making small changes to your code as described above reduced the additional memory allocation to 400 - 500KB on each run (on average, by manual observation of Task Manager).

With that said, the behavior could just be Windows and/or Chrome and their memory management. After leaving the JSFiddle page idle for a while, the memory usage for Chrome dropped back down to where it was before I started running your example. Some sort of garbage collection happened eventually, just maybe not as quickly as you are expecting it to happen.

Upvotes: 0

Mic
Mic

Reputation: 25164

There was a trick to reduce/avoid memory leaks, at least in IE.

You can try it to see if the memory is freed quicker than your current method.
It is to insert first the HTML in the DOM, and then attach the events.

Upvotes: 0

John Fisher
John Fisher

Reputation: 22719

You'll need to be careful about just looking at the browser's memory usage. A more accurate test with that as the measurement would be to run the code many times, then look at the browser memory usage, then run many more times and compare the new number.

Normally, the browser doesn't behave in a way that reflects just the use of javascript. So, it's memory usage can fluctuate without your code necessarily having a leak.

Upvotes: 0

Shaggy Frog
Shaggy Frog

Reputation: 27601

It's not uncommon for a program to allocate memory, see its memory usage go up and then not change when that memory is freed. This is a consequence of how the underlying OS is managing memory and is not necessarily cause for concern, and not necessarily a "problem". You should use other tools, in general, to locate memory leaks in programs (whether they are native code or live in a browser), instead of relying on system tools that track overall process statistics.

Upvotes: 1

Related Questions