The tool is currently in beta and we welcome your feedback (email paolosev [at] microsoft [dot] com, or use the feedback form below).
As many web developers know, it is relatively easy to build a website which results in memory leaks when viewed in Internet Explorer. IE team members have written MSDN articles on leak patterns, and other sites have posted articles with varying tone, depending on the author’s frustration with the problem.
Instead, an IE DOM object is a COM object; therefore its lifespan is ruled by a reference count. Both systems work perfectly in isolation but problems can arise when there are circular references between these two worlds as each side can’t see the entire cycle of these references.
For example, the following code (used to) generate a leak in IE6:
jsObject = document.getElementById("LeakedDiv");
document.getElementById("LeakedDiv").expandoProperty = jsObject;
SetupLeak() function creates a circular reference like this:
However, as some web developers have pointed out, those changes did not solve the problem entirely. IE still leaves behind anything not attached to the tree when the markup is tore down. The previous script, for example, would still leak if the
LeakedDiv object was detached from the markup of the page calling:
before closing the page.
As the problem has already been thouroughly described elsewhere, I won’t go into more details here. Those interested in learning more can find more info in the papers listed in the references section.
The situation will definitely improve in future versions of IE. In the meantime, however, it is useful to have a tool which helps to find potential leaks.
To install it:
- Download the installer and unpack it from the ZIP archive: download link
- Close all the running instances of Internet Explorer.
- Run the setup program jsleaksdetector.msi.
- Enable the new Explorer Bar (in Internet Explorer 7) by selecting the command Tools->Toolbars->Explorer Bar and checking “js memory leaks detector“, as shown (use the Tools menu labeled with the gear icon):
Note that in Windows XP SP2 the new Explorer Bar is also available in the View menu (View->Explorer Bar).
In some cases a reboot might be required to make the leaks detector appear in the list of installed explorer bars. We are now working to reproduce and fix this issue.
- Enable script debugging by selecting Tools->Internet Options->Advanced->Browsing and unchecking Disable script debugging, as shown:
Now a new explorer band will appear at the bottom of Internet Explorer. The tool is now ready to detect memory leaks, not on the current page, however, but beginning from the next page loaded in the browser.
This band is composed of four windows:
- Document tree window
- Memory leaks window
- Call stack window
- Script window
Window #1: Document Tree
The tree uses a color code to represent the state of an HTML document.
The document currently loaded in the current tab of IE is displayed in blue. The tool can detect a document’s memory leaks only after the document has been unloaded. Therefore, expanding the ‘blue’ document node we can see the list of scripts ready for execution, but no leaks yet.
As soon a document is closed (for example refreshing the page or navigating to another page) the system calculates a list of possible leaked DOM objects. If this list is empty, the color of the document is changed to green. If one or more leaks are detected, the color is changed to red.
Script nodes represent script files or script snippets loaded by the current document. Selecting a script node shows the actual content of the script in the script view.
Leak nodes represent DOM object that were (possibly) leaked after the execution of the scripts in the page. Whenever possible the DOM objects are shown in the markup tree, in the position that they occupy at creation time. However, leaked objects in IE7 are usually created dynamically, and then dynamically inserted into the DOM tree. Dynamically created and then leaked objects are just listed as children of the ‘leaks’ node.
Window #2: Memory Leaks
Window #3: Call Stack
For example, in our sample script, the call stack would show the function calls that led to the line:
document.getElementById("LeakedDiv").expandoProperty = jsObject;
as this was the statement that caused the leak.
Window #4: Script
The Script Window serves two purposes:
- When a script node is selected in the Document tree, the Script window shows the script code.
- When an item is selected in the Memory leaks window, the Script window displays the script where (possibly) the memory leak originated, highlighting the statement that attached the JS object to the DOM object.
Together, the four windows that compose the IE band should provide enough debugging information to allow a developer to detect and analyze possible memory leaks.
LEAK DETECTION HEURISTICS
The header of the script window also contains a toolbar with two buttons. The “About” button just displays the current version of the DLL. More interesting is the “Settings” button, which shows the following dialog:
How it works
The Jscript engine is a COM object, and it is instantiated by Trident (mshtml.dll) with a call to CoCreateInstance(). Therefore, the first operation made by the tool will be to intercept the calls to CoCreateInstance made by the mshtml module. There are a few ways to implement this API hooking; in this case the simple technique of overwriting the module Import Table in memory works perfectly. (See Robbins’ “Debugging Applications” for more details).
The technique to do this is a bit tricky. A DOM object is passed to (and accessed by) Jscript through an IDispatch interface; so for each new object that we meet we create a fake COM object that works as interceptor (or wrapper), exposing IDispatch and delegating the calls to the real (contained) IDispatch object.
IE6/IE7: look for circular references. If some DOM object is (a) maintained alive by a reference from the Jscript engine and (b) maintains a reference to one (or more) Jscript objects, then this DOM object could be leaked.
We cannot be sure, since Internet Explorer will try to break circular references and IE7 is quite successful in doing this. So, our heuristic will distinguish the cases based on the version of Internet Explorer, giving us the first two settings options:
- IE6: where all circular references are considered leaks
- IE7: where only the DOM objects detached by the markup at “closing” time could be leaked
Actual leaks: look for leaked DOM elements. If some DOM object has a positive ref count after the page has been completely unloaded, then it is probably leaked. (But even in this case, we cannot be definitely sure, as IE could still keep a reference to the object for some reason and release it later).