Externally Declared Global Variable Leak
Yesterday I was hunting down an Internet Explorer memory leak at the office. I started with disabling all events which might leak, and then began to check them one by one. With a stroke of luck the first event I checked caused the biggest leak, which was several megabytes on each page load. The event wasn’t to blame, though.
In fact the real bug was something much harder to grasp than the closure-induced leak. And, since I couldn’t find it described elsewhere, I’ve decided to coin it the Externally Declared Global Variable Leak. It has been confirmed in IE6 and IE7.
Here’s the problem in a nutshell:
- When you create circular references between
windowobjects - And declare global variables (
someWindow.globalVariable) onwindowobject A, fromwindowobject B (or vice versa) - These variables will leak
- Even if they are not referenced
There are a number of possible solutions:
- Prevent or clear the circular references
- Declare the global variables inside the
windowobject - Use
eval()to declare the variables from another window - Remove the variables
I’ve created three testcases, one leaking, another one leaking, and a non leaking one. For fun I’ve added a ~ 20 MB object to the tests, so the leaking will be rather obvious.
As you can see in the tests the leak occurs if the global variable is declared in the main window. Declaring the circular reference variable – which is global as well – in the iframe window has no effect. This leads me to believe the JScript engine thinks the leaking variables are still referenced, because they were declared by another window object.
So, yet another thing to look out for when developing for IE. Happy leak hunting!




Thanks for fixing this Mark!
Laurens van den Oever | 20 April 2006, 22:48 | link
I don’t know much about memory leaks, but I do know the test (at least the first one, didn’t try the others) crashes Mozilla (1.7.13 xp).
matthijs | 7 May 2006, 14:52 | link
No problems here, Firefox 1.5.0.3 OS X.
Mark Wubben | 7 May 2006, 16:00 | link
Yes but that’s not fair, OS X vs XP :)
matthijs | 7 May 2006, 18:24 | link
This didn’t actually increase my memory at all in IE7 RC1, when i refreshed the page the memory usage significantly dropped, and then went back to where it originally was each time, even waiting 10 mins or so the memory was still steady at where it was.
So, i can’t confirm this, as it’s not happening with me.
Tests:
The first ‘leaking’ one used slightly less memory after the refresh.
The second ‘leaking’ one used the same amount of memory after the refresh.
With the second ‘leaking’ one, Firefox has basically crashed under XP (in all fairness, i only have 1 tab open, yet it’s using more memory than IE7 RC1 with 1 tab open, and is maxing the CPU out at 98%.
Ray | 29 August 2006, 09:46 | link
That would be pretty good news, as this leak is really hard to fix.
Mark Wubben | 30 August 2006, 06:52 | link
It seems that this has been fixed in IE7.
Carlos Aguayo | 9 January 2007, 04:42 | link
I have a doubt regarding the scope of code written in external .js files. If the same .js file is included in two html files and a function in it tries to access a an object in the file that exists in both files (like some table or anchor), which one will be inviked? The one in the calling file or the one which referenced the script last…
Also I would like to know if there are any mechanisms/tools/IDE for writing javascript that executes in all browsers in the same way (meaning, using only the common API supported by all) and which is the best code trimmer (removing space and comments to reduce size) and which one is the best script encoder and will encoding work on all browsers…
Faiz | 12 February 2007, 13:57 | link
I was able to reproduce the results that you describe in my environment (IE 6.0.28 on W2K SP4), but i think it is not a new from of IE leak, but rather a case of the closure cyclic reference pattern [1]. I came to this conclusion after experimenting with [2].
What causes the memory to stay occupied IMHO is the reference to “frameone” which is bound to the variable “one” in anonymous function F that servers as an onload handler of window. If you set “one” to null at the end of F, the memory is freed, because the reference count of “frameone” is 0. If you do not set it to null, the reference count is one, because the context of F is still needed by frameone.onload and the context references “frameone”.
Removing the cyclic reference between the window objects did not resolve the leak.
[1] http://msdn.microsoft.com/library/en-us/ietechcol/dnwebgen/ieleakpatterns.asp
[2] http://tests.novemberborn.net/javascript/memory-leakage/edgvl/leak.html
Robert Cerny | 6 May 2007, 13:54 | link
Having the circular reference is indeed a prerequisite for the leak to occur. However as demonstrated by the non leaking example, declaring the global variable inside the iframe itself stops the leak from occuring, even though there still is a circular reference.
Also, the
onevariable refers to theiframeHTML element, and not the window object in question.Mark Wubben | 6 May 2007, 15:02 | link
When i examine the non leaking [1] example with Drip [2] it still leaks, it is just not a 20 MB leak :-), so what is confusing is, that the Array is actually disposed of ?!?
In the first leaking example, “one” carries a reference to frames.frameone in the property “contentWindow” (which is readonly), so the circular reference looks like this:
frameDivElement (contentWindow)-> frames.frameDiv (onload)-> G (context)-> Local variables of F (one)—> frameDivElement
where “x (property)-> y” means “x references y in property”
[1] http://tests.novemberborn.net/javascript/memory-leakage/edgvl/no-leak.html
[2] http://outofhanwell.com/ieleak/
Robert Cerny | 6 May 2007, 16:09 | link
The point of the test cases is to show the leaking of that 20 MB array. You’re correct with regards to the iframe element, and I assume it’s what’s being leaking according to Drip.
Mark Wubben | 6 May 2007, 17:43 | link
Dear Mark Wubben,
I have mentioned your memory leakage test at my website: http://www.gtalbot.org/BrowserBugsSection/MSIE7Bugs/ Your excellent testcases can reproduce the leakages and are utterly convincing.
I think this sort of bugs (application crash bugs, infinite loop bugs, application hang bugs and memory leakage bugs) are very serious bugs that should be dealt with all the seriousness they deserve, the sooner the better. Their objective severity and gravity should put them above/in front of (prioritization) any layout bug.
It’s very much unacceptable to see those kinds of bugs linger on and on for years before they get fixed… and sometimes they don’t even get fixed because Microsoft does not even seem to know they exist!
Best regards,
Gérard Talbot
Gérard Talbot | 3 September 2007, 05:17 | link
Hi Gérard. Microsoft has been pretty good in fixing the memory leaks with IE 7, and some recent updates for IE 6 on XP. Last time I checked I couldn’t reproduce the EDGVL bug in IE 7.
Mark Wubben | 3 September 2007, 22:27 | link