JavaScript memory usage management - javascript

I am building large website with heavy JavaScript usage, all of my content is being loaded trough ajax, it is very similar to Facebook, and since there is a lot of different pages I need a lot of JavaScript, so what I thought of is to divide my script in to sections, each page would have it's own script file.
Now loading is simple, I just load a new file with each page, but my concern is what will happen if user goes trough 100 different pages and load 100 different script files?
At the moment my website doesn't have that many pages, but I'm quite sure it will grow to nearly 100 unique pages at some point in the future.
So what would happen to the user with slower computer? I'm guessing it would start to slow down a lot since there would be no refresh. From what I have read it is impossible to just unload all events and data from loaded script file in any easy way, and if I were to try that it might cost me a way to much time and effort to do that.
So my question would be, should I just leave it the way it is or try to do something about it? I am currently using jQuery with few plugins, and if I had to guess average file would be around 50-200 lines of code with mostly click events, and ajax calls.
Note, each page objects has it's own prefix for each class, for example: home_header, login_header
So there shouldn't be any conflicts between onClick event listeners and similar things.

Just because you are using AJAX doesn't automatically mean alarm bells with regards to memory usage... you should be more worried about the kind of things that cause memory leaks, and making sure you destruct as well as construct things properly:
http://javascript.crockford.com/memory/leak.html
http://nesj.net/blog/2012/04/javascript-memory-leaks/
http://www.ibm.com/developerworks/web/library/wa-memleak/
What is JavaScript garbage collection?
As a rule, in any large system I tend to create a helper constructor that keeps track of all the items I may wish to destroy at a later date or on page unload (event listeners, large attributes or object structures) all indexed by a namespace. Then when I've finished with a particular section or entity I ask the helper system - I call it GarbageMonkey :) - to clear a particular namespace.
For events it unbinds
For attributes it unsets
For arrays / objects it scans and unsets each key and can do so for sub elements too
For elements it removes and cleans content as much as possible
Obviously for the above to work you need to be wary about leaving variables lying around that can keep a reference to the data you hope to delete. So this means being aware of what garbage collection is, what closures are; and how between them they can keep a variable alive forever!! ..or at least until the browser/tab is destroyed. It also means using object structures rather than vars because you can delete keys in any scope that has access to the object, but you cannot do so for vars.
So do this:
var data = {}, methods = {}, events = {};
methods.aTestMethod = function(){
/// by assigning properties to an object, you can easily remove them later
data.value1 = 123;
data.value2 = 456;
data.value3 = 789;
}
Instead of this:
var value1, value2, value3;
var aTestMethod = function(){
value1 = 123;
value2 = 456;
value3 = 789;
}
The reason being because in the above you can later do this:
var i;
for( i in methods ){ delete methods[i]; }
for( i in data ){ delete data[i]; }
But you can't do this:
delete value1;
delete value2;
delete value3;
Now obviously the above wont protect you from a reference that points directly to a sub element of either methods or data. But if you only pass the methods and data objects around in your code, and keep tidy with regards to attaching methods as event listeners, then even if you do end up with a rogue reference it should only point to an empty object (after you've deleted it's contents that is).

If you recycle variables and don't pollute the global scope, you're on the right track; but as for your question, you should first find out if it is a practical concern.
This can be checked and monitored with a profiler - out-of-the box Chrome is pretty decent for it, just type about:memory in the URL and it'll give you a per-tab breakdown and would even let you compare memory usage between browsers. If you have some automated test scenarios set up (or are willing to navigate through 100 pages manually), such profiling will tell you if there's something majorly wrong with your website.

There is 2 different thing to take care of :
-memory usage
-memory leaks
For long-running webapps, memory leaks should be absolutely avoided, otherwise users will experience browser crashes. To monitor memory use, you can download process explorer :
http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx
Disable all your browser plugins, and then use your app, and perform repetitive tasks. If memory use raises, you got leaks. IE7 - IE8 do leak much more easily than modern browsers, and are much harder to debug, so it is useful to know what is you minim browser compatibility.
For memory usage, a few thing can help decrease the weight of your app :
instead of looping through dom elements and attaching event handlers functions, use event delegation. ED is really a golden gun here.
for IE 7 / 8 var nullification was necessary and I think it still helps for modern browsers(needs some testing). To do so, you need also to name your functions, so that you can remove them from memory. (see pebbl answers for more details on this)
keep control of the dom size. When nodes are added for a feature, they should also be removed when this feature is not used anymore.
add to all of your components some teardown() method that handles unloading.
ok, sorry I am a bit too quick here, but it would be nice to know :
what is your minimum browser
if you have detected leaks
if ED is a sufficient solution (often it is)

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.

Is the garbage collector called after window.location redirection?

say I have the javascript:
/*getAttribute is mootools method for retrieving a named attribute*/
var companyNumber = button.getAttribute('data-company-number');
var payPoint = button.getAttribute('data-pay-point');
window.location = '/Payslip/ListPayslips/?companyNumber=' + companyNumber + '&payPoint=' + payPoint
delete payPoint;//is this necessary?
delete companyNumber;//is this necessary?
Would the delete lines be necessary? And would they even get called?
No its not necessary, after the redirect all variables and instances will be deleted.
To answer the first question, yes. Everything is garbage on unload (unload fired on refresh, redirect or close).
To answer the second question, the deletes will not be hit after the redirect. The JS engine will stop there and fire unload etc.
As for the discussion around memory management and explicit variable deletion, here are some considerations:
Good memory management can become important when developing larger web apps that are left open in browser for long periods of time, especially when the target client browsers can be older or on slower machines or mobile devices.
In these cases, where you declare variables to hold temporary information, particularly large objects, you may choose to delete these to free them up for garbage collection. It is my opinion that you should avoid new declarations if they are not necessary and re-use objects where you can - but perhaps not at the expense of readability ;)
To add to 'Corey Ogburn's point, delete itself does not free memory, but disconnects a variable from it's value. It is this that frees the variable for garbage collection.
Yes, you lose all the variables if the redirect loads in the current frame/document. The best way to handle this is to create a couple of divs and any redirects need to be loaded in the other div. For instance, you could have a header and main div. Your JS can now reside in the page and any redirects should be loaded into the main div. That way you are preserving state.
An alternative is to use the HTML5 local/session storage.
EDIT:
Your second question which is at the bottom regarding delete. No, delete is not necessary. Others have responded with links and reasons why.

Can I trigger JavaScript's garbage collection?

I want to trigger JavaScript garbage collection. Is it possible? Why would I want to, or not want to, do this?
I went out on a small journey to seek an answer to one of your questions: Is it possible?
People all over town are saying that deleting the references will do the trick. Some people say that wiping the object is an extra guarantee (example). So I wrote a script that will try every trick in the book, and I was astonished to see that in Chrome (22.0.1229.79) and IE (9.0.8112.16421), garbage collection doesn't even seem to work. Firefox (15.0.1) managed without any major drawbacks apart from one (see case 4f down below).
In pseudo-code, the test goes something like this.
Create a container, an array, that will hold objects of some sort. We'll call this container Bertil here on.
Each and every object therein, as an element in Bertil, shall have his own array-container declared as a property. This array will hold a whole lot of bytes. We'll call any one of Bertil's elements, the object, Joshua. Each Joshua's byte array will be called Smith.
Here's a mind map for you to lean back on:
Bertil [Array of objects] -> Joshua [Object] -> Smith [Array of bytes] -> Unnamed [Bytes].
When we've made a mess out of our available memory, hang around for a sec or two and then execute any one of the following "destruction algorithms":
4a. Throw a delete operand on the main object container, Bertil.
4b. Throw a delete operand on each and every object in that container, kill every Joshua alive.
4c. Throw a delete operand on each and every array of bytes, the Smiths.
4d. Assign NULL to every Joshua.
4e. Assign UNDEFINED to every Joshua.
4f. Manually delete each and every byte that any Joshua holds.
4g. Do all of the above in a working order.
So what happened? In case 4a and 4b, no browser's garbage collector (GC) kicked in. In case 4c to 4e, Firefox did kick in and displayed some proof of concept. Memory was reclaimed shortly within the minute. With current hardcoded default values on some of the variables used as test configuration, case 4f and 4e caused Chrome to hang, so I can't draw any conclusions there. You are free to do your own testing with your own variables, links will be posted soon. IE survived case 4f and 4e but his GC was dead as usual. Unexpectedly, Firefox survived but didn't pass 4f. Firefox survived and passed 4g.
In all of the cases when a browser's GC failed to kick in, waiting around for at least 10 minutes didn't solve the problem. And reloading the entire page caused the memory footprint to double.
My conclusion is that I must have made a horrible error in the code or the answer to your question is: No we can't trigger the GC. Whenever we try to do so we will be punished severely and we should stick our heads in the sand. Please I encourage you to go ahead, try these test cases on your own. Have a look in the code were comment on the details. Also, download the page and rewrite the script and see if you can trigger the GC in a more proper way. I sure failed and I can't for the life of me believe that Chrome and IE doesn't have a working garbage collector.
http://martinandersson.com/dev/gc_test/?case=1
http://martinandersson.com/dev/gc_test/?case=2
http://martinandersson.com/dev/gc_test/?case=3
http://martinandersson.com/dev/gc_test/?case=4
http://martinandersson.com/dev/gc_test/?case=5
http://martinandersson.com/dev/gc_test/?case=6
http://martinandersson.com/dev/gc_test/?case=7
You can trigger manually JavaScript garbage collector in IE and Opera, but it's not recommended, so better don't use it at all. I give commands more just for information purpose.
Internet Explorer:
window.CollectGarbage()
Opera 7+:
window.opera.collect()
Garbage collection runs automatically. How and when it runs and actually frees up unreferenced objects is entirely implementation specific.
If you want something to get freed, you just need to clear any references to it from your javascript. The garbage collector will then free it.
If you explain why you even think you need to do this or want to do this and show us the relevant code, we might be able to help explain what your alternatives are.
Check your code for global variables. There may be data coming through an ajax call that is stored, and then referenced somewhere and you did not take this into account.
As a solution, you should wrap huge data processing into an anonymous function call and use inside this call only local variables to prevent referencing the data in a global scope.
Or you can assign to null all used global variables.
Also check out this question. Take a look at the third example in the answer. Your huge data object may still be referenced by async call closure.
This answer suggests the following garbage collection request code for Gecko based browsers:
window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
.getInterface(Components.interfaces.nsIDOMWindowUtils)
.garbageCollect();
Came across this question and decided to share with my recent findings.
I've looked to see a proper handling of a WeakMap in Chrome and it's actually looks okay:
1) var wm = new WeakMap()
2) var d = document.createElement('div')
3) wm.set(d, {})
at this stage weak map holds the entry cause d is still referencing the element
4) d = null
at this stage nothing references the element and it's weakly referenced object, and indeed after a couple of minutes entry disappeared and garbage collected.
when did the same but appended the element to the DOM, it was not reclaimed, which is correct, removed from the DOM and still waiting for it to be collected :)
Yes, you can trigger garbage collection by re-loading the page.
You might want to consider using a Factory Pattern to help re-use objects, which will greatly cut down on how many objects are created. Especially, if you are continuously creating objects that are the same.
If you need to read up on Factory Patterns then get yourself this book, "Pro Javascript Design Patterns" by Ross Harmes and Dustin Diaz and published by APress.
I was reading Trevor Prime's answer and it gave me a chuckle but then I realized he was on to something.
Reloading the page does 'garbage-collect'.
location.reload() or alternatives to refresh page.
JSON.parse/stringify and localStorage.getItem/setItem for persistence of needed data.
iframes as reloading pages for user experience.
All you need to do is run your code in an iframe and refresh the iframe page while saving useful information into localStorage. You'll have to make sure the iframe is on the same domain as main page to access its DOM.
You could do it without an iframe but user experience will no doubt suffer as the page will be visibly resetting.
If it is true that there is no way to trigger a GC, as implied by the other answers, then the solution would be for the appropriate browser standards group to add a new JavaScript function to window or document to do this. It is useful to allow the web page to trigger a GC at a time of its own choosing, so that animations and other high-priority operations (sound output?) will not be interrupted by a GC.
This might be another case of "we've always done it this way; don't rock the boat" syndrome.
ADDED:
MDN documents a function "Components.utils.schedulePreciseGC" that lets a page schedule a GC sometime in the future with a callback function that is called when the GC is complete. This may not exist in browsers other than Firefox; the documentation is unclear. This function might be usable prior to animations; it needs to be tested.

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.

Selectors and performance

Is there any benefit to performance when I do the following in Mootools (or any framework, really)?:
var elem = $('#elemId');
elem.addClass('someClass');
elem.set('some attribute', 'some value');
etc, etc. Basically, I'm updating certain elements a lot on the DOM and I was wondering if creating a variable in memory and using that when needed was better than:
$('#elemId').addClass('someClass');
$('#elemId').set('some attribute', 'some value');
The changes to $('#elemId') are all over the place, in various different functions.
Spencer ,
This is called caching and it is one of the best practices.
when you say
$('#elemId');
It will go and query the DOM everytime , so if you say
var elem = $('#elemId');
elem acts as a cache element and improves performance a lot.
This is manly useful in IE as it has memory leaks promblem and all
ready this document which is really good
http://net.tutsplus.com/tutorials/javascript-ajax/14-helpful-jquery-tricks-notes-and-best-practices/
It depends how you query the dom. Lookups by ID are extremely fast. Second most is css classes. So as long as you're doing it by only a single ID (not a complex selector containing an id), there shouldn't be much of a benefit. However, if you're using any other selector, caching is the way to go.
http://code.google.com/speed/page-speed/docs/rendering.html#UseEfficientCSSSelectors
https://developer.mozilla.org/en/Writing_Efficient_CSS
You first approach is faster then your second approach, because you "cache" the search on #elemId.
Meaning the calls to addClass and set don't require extra lookups in the DOM for your element.
However! You can link function calls:
$('#elemId').addClass('someClass').set('some attribute', 'some value');
Depending on your application caching or linking might work better, but definitely not identical sequential lookups in the same block.
Depending on the situation, caching can be as much as 99% faster then using a jQuery object every time. In the case you presented it will not make much difference. if you plan to use the selector many times, you should definitely cache the object as a variable so it doesn't get created everytime you run it.
A similar questions was answered at Does using $this instead of $(this) provide a performance enhancement?.
Check performance log http://jsperf.com/jquery-this-vs-this
You are considering using a local variable to cache a value of a potentially slow lookup.
How slow is the call itself? If it's fast, caching won't make much a difference. If it's slow, then cache at the first call. Selectors vary significantly in their cost-- just think about how the code must fine the element. If it's an ID, then the browser provides fast access, whereas classes and nodes my require full DOM scans. Check out profiling of jQuery (Sizzle) selectors to get a sense of these.
Can you chain the calls? Consider "chaining" method calls where possible. This provides the efficiency without introducing another variable.
For your example, I'd write:
$('#elemId').addClass('someClass').set('some attribute', 'some value');
How does the code read? Usually if the same method is going to be called multiple times, it is clearer to DRY it up, and use a local variable. The reader then understands the intent better-- you don't force them to scan all the jQuery calls to verify that they are the same. BTW, a fairly standard convention is to name jQuery variables starting with a $-- which is legal in Javascript-- as in
var $elem = $('#elem');
$elem.addClass('someClass');
Hope this helps.

Categories