Should you dispose of jQuery objects? - javascript

A colleague of mine always sets their jQuery variables to null, to effectively dispose them, once they're finished with, e.g:
var bigThing = $(body);
// ...
// Do some stuff
// ...
bigThing = null;
Is that really necessary?

If you encapsulate your code into functions thats unnecessary as after the function finishes the local variables will be killed anyway when no reference of them is used elsewhere.
Holding onto a selector/variable (caching) might have some positive effect tho if you need to select the same thing over and over again versus selecting it only once and keeping the variable.

Short answer: no that's hardly ever necessary if you're using jQuery.
It depends on what you did with it. If you didn't attach any event handlers to the DOM Node, the garbage collector will clear it when it's no longer referenced.
But even if you did attach event handlers, jQuery will take care of them in functions like .remove() and .empty() by detaching all event handlers for you. So as long as you use jQuery to interact with the DOM, you're safe.
Without jQuery, if you've attached an event handler to the Node, the GC won't clear it, even after you've removed the Node from the DOM tree and you no longer have any references to it. This is because the DOM Node contains a reference to a JavaScript object (i.e. the event handler) and vice versa. This creates a cyclic reference across two separate systems; something most garbage collectors have trouble with.
For further reading I point you to Douglas Crockford's article on Memory Leaks.

It's not necessary but good habit to remove reference and release the memory

Though not entirely necessary, this can be done to ensure that the GC clears it in its next run (which it'll anyway do for all allocations to which you don't have even 1 reference).
In your example though, the $(body) object (the jquery extended object, not the DOM body object) will be cleared if you set bigThing to anything else (not necessarily null)

Javascript has its own garbage collector. So, it appears that you don't need to explicitly dispose of the objects.
But due to various reasons, like bad implementation of garbage collector etc., it may happen that their are some memory leaks.
By nullifying them explicitly, you specify to the browser that this memory has to be cleared in next garbage collection.
In conclusion, though it is not necessary to do this, it will be a good practice to nullify the JQuery/javascript objects.

Related

Does deleting variables before closing the tab/window help releasing memory?

I'm maintaining a JavaScript code where a function that does some heavy processing to generate arrays saves the results in a cache variable inside the function itself. It's implemented like this:
function heavyProcessingStuff(x) {
if(heavyProcessingStuff.cache == undefined)
heavyProcessingStuff.cache = [];
if(heavyProcessingStuff.cache[x] != undefined) {
return heavyProcessingStuff.cache[x]
} else {
return heavyProcessingStuff.cache[x] = x + 1
}
}
The weird thing is that there's a function executed when the page is unloaded that manually deletes every property of the cache variable, like this:
for (n in heavyProcessingStuff.cache) {
delete heavyProcessingStuff.cache[n]
}
I'm confused about why this was implemented this way.
Is this specific for some weird corner case? Is there any motivation to do so? Doesn't/shouldn't the browser garbage collect everything when the page closes?
Javascript uses garbage collection and it is best not to free memory explicitly. Good reading on this is in "De-referencing Misconceptions" in the article "Writing Fast, Memory-Efficient JavaScript".
A quote from the article:
It’s not possible to force garbage collection in JavaScript. You
wouldn’t want to do this, because the garbage collection process is
controlled by the runtime, and it generally knows best when things
should be cleaned up.
Without seeing the full context, there is one other possibility:
Earlier versions of IE (I know IE6 was susceptible), used a simple reference counting system for garbage collection. The trouble is that the DOM and JavaScript kept separate reference stacks.
This allowed for a situation to develop where the DOM (via an expando property) could hold onto a JavaScript reference -- and the JavaScript held onto a DOM reference.
This circular references would create a memory leak that lived on beyond the page, and the memory was only released when the page window was closed.
It was common to use the unload event to free memory and release any event handlers in an effort to avoid this.
In Chrome and Internet Explorer (or any browser that implements a process-per-tab model), you're right, there's absolutely no value. In fact, it's wasting CPU time to try and delete, since often when a tab is closed a process is killed, freeing up all non-shared resources.
For browsers that are a single process (Firefox still is, though progress is underway to change that), it's possible this could make the garbage collector do its work faster, if the reference counts get decremented to 0, but it's probably also pointless. Other than very old (IE6 for example) browsers, every modern garbage collector will probably sweep away everything on the next pass regardless of whether you explicitly remove references or not.

Precise explanation of JavaScript <-> DOM circular reference issue

One of the touted advantages of jQuery.data versus raw expando properties (arbitrary attributes you can assign to DOM nodes) is that jQuery.data is "safe from circular references and therefore free from memory leaks". An article from Google titled "Optimizing JavaScript code" goes into more detail:
The most common memory leaks for web applications involve circular
references between the JavaScript script engine and the browsers' C++
objects' implementing the DOM (e.g. between the JavaScript script
engine and Internet Explorer's COM infrastructure, or between the
JavaScript engine and Firefox XPCOM infrastructure).
It lists two examples of circular reference patterns:
DOM element → event handler → closure scope → DOM
DOM element → via expando → intermediary object → DOM element
However, if a reference cycle between a DOM node and a JavaScript object produces a memory leak, doesn't this mean that any non-trivial event handler (e.g. onclick) will produce such a leak? I don't see how it's even possible for an event handler to avoid a reference cycle, because the way I see it:
The DOM element references the event handler.
The event handler references the DOM (either directly or indirectly). In any case, it's almost impossible to avoid referencing window in any interesting event handler, short of writing a setInterval loop that reads actions from a global queue.
Can someone provide a precise explanation of the JavaScript ↔ DOM circular reference problem? Things I'd like clarified:
What browsers are effected? A comment in the jQuery source specifically mentions IE6-7, but the Google article suggests Firefox is also affected.
Are expando properties and event handlers somehow different concerning memory leaks? Or are both of these code snippets susceptible to the same kind of memory leak?
// Create an expando that references to its own element.
var elem = document.getElementById('foo');
elem.myself = elem;
// Create an event handler that references its own element.
var elem = document.getElementById('foo');
elem.onclick = function() {
elem.style.display = 'none';
};
If a page leaks memory due to a circular reference, does the leak persist until the entire browser application is closed, or is the memory freed when the window/tab is closed?
It's probably not worth reproducing all the content in these links, so I'd suggest you do some reading and a look at the other Google search hits:
javascript, circular references and memory leaks
Do you know what may cause memory leaks in JavaScript?
http://www.ibm.com/developerworks/web/library/wa-memleak/
http://www.ibm.com/developerworks/web/library/wa-sieve/index.html?ca=drs-
http://code.google.com/p/google-web-toolkit/wiki/UnderstandingMemoryLeaks
The worst memory leaks are in IE6 where the leaks are permanent (even after you leave the affected web page). The other leaks are generally only while you're on that specific page and get cleaned up when you leave the page.
The fact is that the browser is supposed to be able to handle circular references. It's supposed to be able to see that even though a DOM element is still being referred to by a JavaScript element, that the JavaScript element itself only exists because the DOM element is still alive and thus there is no true outside reference left to the DOM element. It is this recognition that older versions of IE were bad at. Thus in your code references that involve event handlers, the garbage collector needs to be smart enough to know that the only references left to the DOM element in JavaScript are references that themselves would go away when the DOM element and it's event handlers were removed - thus there are no true outside references so it's safe to remove both the DOM element and the event handler. This is a more complicated version of the general circular reference problem that all garbage collectors have to handle where object A refers to object B and object B refers to object A, but no other object refers to either A or B, thus both can be freed.
jQuery's .data() makes things more reliable because the older versions of IE had a particular problem with properties that were added to a DOM element and did not handle circular references properly involving the data in those properties and thus would not free things when it should have (a leak). .data() works around that by only using one added property on the DOM element which is a safe, non-leaking string. That string is then a key into a JavaScript object that can contain all the properties that you would like to associate with the DOM element. Because these properties are all stored in plain JavaScript, where the browsers don't have the circular reference bugs, doing it this way doesn't cause leaks.
It's important to realize that there may still be some circular references and that's OK. The work-around is to move the circular references to a place that the browsers handle them appropriately rather than putting them in the place that the browsers have bugs.

What does backbone.js do with models that are not used anymore

Lately I am diving into the whole client-side MVC/MVVM design paterns, and the one I am particularly interested in is backbone.js.
One thing I do not fully understand is what happend to the models when they are not really needed anymore.
Let's say we have an app that has users and products. We have user models/views and product models/views
NOTE: for simplicity sake we are not a user. We can just CRUD users / products.
When I enter the products page, I assume we load the model and the view corresponding to this.
What happens when we leave the page and enter the users page. A user model/view is loaded, but the products are also still loaded.
Do we keep them loaded, does backbone take care of that for you, or do you explicitly need to end certain objects.
Backbone does not explicitly handle cleaning up objects for you. It's 50/50 you and the JavaScript runtime.
JavaScript is a garbage collected language like Java, C#, Ruby, and others. The basic of a garbage collected languages is that an object that is still referenced by your application will not be cleaned up. The counter to that is when an object is no longer referenced by your application, will be cleaned up.
JavaScript in general:
When you create a variable, you can either scope that variable to a local function or as a global variable.
Global variables are never cleaned up by the garbage collector, during the life of the page. The only time they are cleaned up is when you leave the HTML page behind entirely - navigate to a different page and force the browser to load the new page from the server (doing a complete server refresh) or closing the browser or browser tab.
Function scoped variables are cleaned up when the variable falls out of scope - that is, when the function has exited and there are no more references to it. There are a few exceptions to this: return values and closures.
A return value is held in your app by assigning the return value to another variable. A return value falls under the same general rules, but the variable is now in a different function. Once that variable goes out of scope, it can be cleaned up.
A closure allows a parent scope to provide values that a descendant scope can access. When the descendant scope is cleaned up, the parent's closured variable may be allowed to be cleaned up (assuming nothing else is holding on to it).
Objects with attributes and functions fall under the same rules. An object can reference another object or function by having an attribute assigned to it: myObj.foo = thatObj.
The DOM (Document Object Model - the HTML in your app) is a JavaScript object. Events and other references to your DOM work the same as any other reference. If you have an object handling a DOM event, it has a reference in your app and it won't be cleaned up by the garbage collector. If you want it cleaned up, you have to remove all references to it - including the DOM reference from the event handler.
Cleaning Up Memory
The general rule is that if you are loading data in to a backbone collection or object and you want that object to be cleaned up so it's not using anymore memory, you must remove all references to that object. This is just the standard JavaScript garbage collection rule.
You cannot force garbage collection, but you can force a variable to de-reference the thing it points to using the delete keyword in JavaScript: delete myVar
Backbone
Backbone is JavaScript so it falls under the same rules. There are some interesting uses of closures and references in Backbone that you need to be aware of, which will help you to know when you need to manually clean up some objects.
For example: events. An even handler / callback method works by having a reference between the object that triggers the event and the callback that handles the event. This is one of the easiest places to cause memory leaks in a Backbone app and I discuss it in detail, here: http://lostechies.com/derickbailey/2011/09/15/zombies-run-managing-page-transitions-in-backbone-apps/
Other than being aware of how events work in terms of references, just follow the standard rules for manage memory in JavaScript and you'll be fine. Once you remove all references to that collection of User objects, they'll be cleaned up.
Note that if you console.log() your model (at least in Chrome) it will remain in memory because the console has a reference to it.
I got mad because of this. If you see memory leak, try clearing your console and run your profile again. If you had the same problem i had, it's gone :)

How do you clear memory in Javascript?

var Obj = function(){}; var X = new Obj();
will X = null properly clear memory?
Also would this be equivalent?
var Obj = function(){};
var X = {};
X.obj = new Obj();
delete(X.obj);
EDIT
It would seem that although deleting X.obj would NOT immediately clear memory, it would help the garbage collection. If I don't delete X.obj, there would still be a pointer to an object and so the GC may not clean it up.
Although I'm picking #delnan's answer, if you're reading this you should def also catch Benubird's article.
I also notice I accidentally wrote delete(X) originally instead of delete(X.obj) - sorry.
The short answer is that you don't. delete simply removes a reference (and not in the way you try to use it, see the above link - delete is one of those language features few people actually understand), nothing more. The implementation clears memory for you, but it's not your business when (and even if, strictly speaking - this is why one shouldn't rely on finalizers in GC'd languages that offer them) it does. Note though:
Only objects that can be proven to be unreachable (i.e. no way to access it) to all code can be removed. What keeps references to whom is usually fairly obvious, as least conceptually. You just need to watch out when dealing with lots of closures, as they may capture more variables than you think. Also note that circular references are cleaned up properly.
There's a bug in old (but sadly still used) IE versions involving garbage collection of JS event handlers and DOM elements. Google (perhaps even SO) should have better material on my memory.
On the plus side, that means you won't get dangling pointer bugs or (save of course the aforementioned pitfalls) memory leaks.
No, that will not clear memory.
Read this:
http://perfectionkills.com/understanding-delete/
No - Javascript runs GC when it feels like it.
The Delete method only deletes the reference - not the object. Any other references would be left out in the open waiting for the garbage collector.
JavaScript has its own GC, and it will run around and clean things up when nothing refers to them anymore.
I still think it's a good practice to null objects.
Deleteing an object also helps the GC because it will see something dangling, and say "I'm going to eat you because you're all alone (and now some cynical laugh)".
You should look at Deleting Objects in JavaScript
Even though there's a GC, you still want to ensure your script is optimized for performance as peoples computers, browsers, and fricken toolbars (and the number of them), will vary.
Generally speaking, memory management in Javascript is user-agent-specific. The basics of the garbage collector are through reference-counting. So, by setting a reference to null (using the delete keyword or by explicit assignment), you can assure yourself that a reference will be cleaned up, IF the object does not have any references that will live outside of its creation scope. That being the case, the GC will have already cleaned up any objects or variables whose scope has ended without your explicitly setting it to null.
There are some things to take care of, though - circular references are easy to create in JS, especially between a DOM element and an object. Care must be taken to clear (or not create in the first place) references to and/or from DOM elements within objects. If you do create a to/from reference related to DOM, be sure to explicitly clean them up by setting the references to null - both on your object and on the DOM element. Simply setting a parent object to null is not sufficient if there are child objects with references to/from DOM or localStorage because those references will live on, and if there was any reference from the child to the parent, then the parent will live on in memory because of that reference.
Web pages can actually leak trash in your memory this way - after you navigate away, the circular references keep objects and DOM elements in memory until you've restarted the browser!
An article on the subject: http://docstore.mik.ua/orelly/webprog/jscript/ch11_03.htm, and another detailed look: http://blogs.msdn.com/b/ericlippert/archive/2003/09/17/53038.aspx
JavaScript memory is generally handled similarly to Java - I mean there is (or there should be) a garbage collector which would delete the object if there is no references to it. So yes, simply "nullifying " the reference is the only way you should "handle" freeing memory, and the real freeing is the JS host part.

Renaming the 'this' keyword

I'm concerned that I might be using a code pattern that leaks memory. Here's a pseudocode example:
window.user = new User();
user.getBasicInfo(function(basicInfo){
user.name = basicInfo.name;
user.getDetailedInfo(function(detailedInfo){
user.favoriteColor = detailedInfo.favoriteColor;
});
});
In other words, I'm not using the 'this' keyword to refer to the user object; I'm referring directly to the user object stored within the window object.
Obviously, the JavaScript 'this' keyword has given lots of people lots of trouble. I've seen some people rename 'this' to make it more clear as they descend a scope chain:
window.user = new User();
user.getBasicInfo(function(basicInfo){
var userInOuterScope = this;
userInOuterScope.name = basicInfo.name;
userInOuterScope.getDetailedInfo(function(detailedInfo){
var userInInnerScope = this;
userInInnerScope.favoriteColor = detailedInfo.favoriteColor;
});
});
Not as pretty, but it seems like the scope chain might be less convoluted in that case.
Can the first approach leak memory? Can the second? To avoid leaking memory, must I pass everything as a parameter (and never refer to objects outside of the current scope)?
The potential to "leak memory" is not something relevant to the question you seem to be asking. That is, neither of the approaches have implications on memory use, at least not in any way clear to me.
The reason you might prefer to make use of the this facility in your code is that you might want a population of objects. In your case, you're apparently using the object as a singleton, so it makes no difference. However, that's really a special case, and you'd quickly find that it doesn't work so well if you've got 100 "User" objects.
Preserving the value of this (and it's not really "renaming" this; it's copying its value into another variable) inside a closure could result in a memory leak, or rather, could be part of a larger memory-leaking setup, but it's not problematic in and of itself. Making copies of object references is something that happens all the time.
edit — the "leakage" problem with closures comes about when a combination of things happens:
Some objects are referenced by variables in the closure scope (not weird or harmful in and of itself);
Functions with references to the closure scope "escape" from a function call, either by being returned or by being exported via global state side-effects (like registering an event handler) (also not weird or harmful in and of itself);
The population of these exported functions grow, or the functions themselves allocate more room when they're invoked and preserve references to the space allocated in the closure, or the exported functions end up directly referenced by DOM nodes (this is particularly a problem in IE).
Really, JavaScript doesn't have any unique problems with memory leaks that any language with real closures has. For a vast amount of actual JavaScript software in this world (utility code wired into web pages), it's pretty rare that memory leakage is a problem, I suspect, though the IE issue with DOM references has probably crashed a few browsers over the years (which probably hardly surprised the hapless users).
I don't like pushing frameworks on people, but it's definitely true that framework authors must worry about this stuff. Trusting in your framework to keep the DOM clean by making sure you only attach event handlers and data to the DOM via framework facilities is therefore a Good Idea.
It doesn't appear that you have any circular references in your code, so I wouldn't worry about memory leaks. You're not setting objects equal to other objects as far as I see ( http://jsfiddle.net/Akkuma/UTL3B/ as a quick example how it could lead to memory leaks).
Here are a few references on memory leaks
http://www.ibm.com/developerworks/web/library/wa-memleak/
http://www.javascriptkit.com/javatutors/closuresleak/index.shtml
http://javascript.crockford.com/memory/leak.html
Additionally, you can use Chrome's Heap Snapshot tool to be able to tell whether or not you are having memory leaks worth worrying about.
JavaScript's this is not the same this like Java's or C#'s. It represents the current context of something being executed.

Categories