We all know that the memory leaks in Internet Explorer are horrible. However we’ve found ways (often making beautiful code really ugly) around these issus. My general guideline has always been to make sure that you don’t keep any reference betwen JScript objects and DOM/COM objects (and the other way around) as well as make sure that no DOM/COM object is in the scope when you use anonymous functions (since the closure will contain a reference to the DOM/COM object).
I usually say that as long as you are using only native JScript objects the garbage collector will collect these. However I’ve found a case where this is not the case. The reason for the problem is described be Eric Lippert here. I’ll show you when this problem manifests itself and then discuss ways to get around it.
var obj = {};
...
obj.foo = ...
...
delete obj.foo
That’s all. The problem here is that even though we delete the field foo JScript keeps this key occupied and adds a flag so that it looks like it has been removed to JScript code. The reason according to Eric Lippert is that COM caches the references to the field and adding another key with the same name should be still be accessible from the cached reference. (Why?).
Here is a larger code snippet that does the above a lot of times so that you can actually see that it leaks memory.
// create an object to use as a hash/dictionary/cache/lookup table
var obj = {};
// define a function to make the testing easier
function addAndRemove() {
var key;
for (var i = 0; i < 10000; i++) {
// generate fairly unique key
key = Math.random();
// add key value pair
obj[key] = key; // the value is not relevant
// and then remove the key
delete obj[key];
}
}
window.setInterval("addAndRemove()", 50);
This does not leak very much memory but if you have a hash table like structure that is long lived where a lot of add and removes are done to it you might run into problems. This is usually the case for caches and other lookup tables. So in these cases it makes sense to work around this JScript issue.
One way to work around this is to clone the object and let it replace the old object. This is fast if the hash is empty but O(n) otherwise where n is the number of keys currently in the hash.
var tmp = {};
for (var k in obj) {
if (obj.hasOwnProperty(k)) {
tmp[k] = obj[k];
}
}
obj = tmp;
You might want to build your own class to handle this internally. When the ratio between the count of the items added to the actual items in the hash is greater than a certain value you can replace the old hash object with a new one as done above.