JScript Object Memory Leak
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.
August 5th, 2005 at 4:34
Does that mean all the times where I changed your code to use “delete” is wrong? Doh! Me and my meddlesome hackery.
August 5th, 2005 at 10:40
It means that a delete will still keep the key string and few internal flags (as well as most like the hashed value of the string). However if the GC later releases that object the memory is freed. It is only an issue if the object is keept for a long time.
In the code above; If you recreate obj after the loop JScript does not leak any more.
August 11th, 2005 at 23:53
Hello,
Another “memory leak”-phonomenon manifest itself through the use of “filter” in CSS declarations. When a filter, any, is applied to an object than the allocated memory for this isn’t released, even if the object that is attached to is deleted or the removal of the CSS-rule. Actually, just the declaration “filter:;” causes the allocation of memory and sluggish browser. Extremly annoying behaviour…
I have mentioned this at Dave Massy’s bussy blog, hopefully this (among others) will be attended to.
/hbi
August 11th, 2005 at 23:56
I thought that setting style.filter = “” before removing the element worked?
August 19th, 2005 at 18:39
HAPPY BIRTHDAY Oracle!!! =)
Peace, health, etc…
This is a message from one of your friends that you never met.
Cheers,
August 30th, 2005 at 22:02
I’m curious why you would use delete instead of assigning a null value?
August 30th, 2005 at 22:12
Because delete removes the key/value pair. Assigning null keeps the key and changes the value. If you just change to null the in operator (and hasOwnAttribute method) and for in loops will still include the key/value pair you want to remove
August 13th, 2007 at 13:13
What happens in the following code…
var obj = {};
…
obj.foo = {
a: function() { this.a = “”; this.b = 10; }, b: function() { … } };
…
var myObj = new obj.foo.a();
delete obj.foo