My job is simple. Write desktop-like applications in javascript/php on firefox that might not be restarted for weeks. Ohhh and you have no access to the servers so it will all have to be self sufficient if something goes wrong. ouch. Not so simple. If it was just me, no big deal some coding standards and practices could get the team on the same page. However I also have to deal with 10-30+ 3rd party teams that wish to develop web apps for this hardware as well. Oh, did I forget the boxes are a zippy 800mHz and I only have around 150MB of ram to play with?

The major problem with doing desktop style web apps is that the application might never be reloaded. So a user could literally have your app going for 3 weeks at a time without restarting either the browser or the server. How can you avoid shooting yourself in the foot with all the javascript code needed to get 100+ pages or even 1000 pages functioning?

Let's step back and look at how firefox deals with your memory. When firefox starts up it allocates a certain amount of memory to function. Let's for numbers sake say 20MB. Now a user goes to your web page and has to load up all the HTML, CSS, Javascript, Images, etc. Let's say you have a big ol data object in javascript that contains a huge array. That array takes up 40MB of memory(told you it was huge). Now Firefox has allocated 60 MB of memory for your app to use. If you never free that memory it will remain at 60MB. As the user does other things, more memory is being allocated for new javascript objects. If you're just using that one object for a particular page on your site then having that extra 40MB of space being wasted is really poor coding practice.

You would think you'd be able to remove that script from the DOM and life would move on, giving you back your memory. WRONG. Removing the script from the DOM does nothing for memory de-allocation. You might see the script missing from the DOM but that object still has memory allocated to it. The key is to Null out that object. e.g.: myObj = null; A slight problem with that is that firefox will not give you back your 40MB you asked for before. It says "eh, thanks for the memory... I think I'll hold on to most of it just in case homie". So maybe you'll free up 10MB of memory. Now your object is null'd and you still see firefox running at 50MB of memory. Well that's not fair! I want my memory back! Worry not, because even though memory is definitely still allocated to firefox and you won't get it back, it is free memory. So even though it says 50MB, you still have that 30MB free that firefox is waiting for you to use in the future. So the problem becomes... firefox will grow to the size of your largest object. At least in javascript terms.

To test this theory I created a simple web page that does the following:
Loops 20 times, creating an object, then filling an array of that object with a string 1 million times over, then nulls out that object.
After the test firefox went from 20MB to 60MB back to 50MB. So after 20 iterations of creating a huge data object and then null'ing it out, firefox was left right where I hoped it would. Back to the size of the largest null'ed out object.

So what does this mean in the real world? Well #1 is use objects for all page specific functionality. For example, let's say you have a shopping cart web page and a user account creation web page. Both most likely have completely different javascript needs. Instead of creating functions such as:


function checkUserName(name)
{ // do something here }

onclick=checkUserName(name);



Make them methods of objects. This will allow you to have simple destructor methods that only need to worry about deleting one object after leaving a page instead of having to worry about all those functions that are taking up memory, or storing data in un-needed global variables. So change that to:


// constructor
function userAccount()
{

}

userAccount.prototype.checkName = function(name)
{ // do stuff here }

var userAct = new userAccount;

onclick=userAct.checkName(name);

// when you're done with it, just null it out
userAct = null;


Boom, now you have your memory back. If you do find yourself with large data structures, try and break them up into small objects that are essentially required. Remember, firefox will grow to the largest amount you request. So request small things and your memory "should" stay in a reasonable place. This may seem like a small example but when you start getting into pages that require 5,000 lines of JS and huge arrays of data it starts to become a big deal to clean up after yourself. Especially for apps like mine that run in closed environments.

What I've come up with is having a basic object storage/removal system. Anytime I need to create an object I use a special function I have that keeps that object in an array. Then when I need to load a new section of a page I automatically null that object out. Thereby cleaning it up without having to worry.

I also tested the difference between just null'ing the object and actually nulling each element of the objects array, then null'ing out the array, then null'ing the object. There was no difference in memory consumption. Which is nice. So you just have to null out your unused objects and you should be good to go.

Enjoy.

Ready for More?

Follow Me @jimplush