Friday, January 25th, 2008
Microsoft JavaScript Memory Leak Detector
Paolo Severini, a Microsoft employee in Dublin, has build a JavaScript Memory Leak Detector that detects leaks with knowledge of the difference between IE 6 and IE 7.
How does it work?
Like any IE Band, the JavaScript Memory Leak Detector is a COM in-process DLL loaded in the Internet Explorer process. The fact of living inside the IE process allows it to easily intercept some of the API calls made by the IE code. In this case, we are interested in intercepting every call that creates a Jscript engine.
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).
At this point we can substitute our own Jscript engine in place of the real engine. By implementing all the ActiveScript interfaces exposed by a Jscript engine and delegating all the calls to an instance of the real Jscript engine, the tool can transparently intercept all the interactions between Trident and Javascript and still have Internet Explorer to run correctly.
Now, a Jscript engine by itself has no notions of Internet Explorer and its DOM objects. It is IE that registers the root (window) object to the engine and loads into the engine all the scripts contained or loaded by a HTML document. Since we are intercepting all the calls to Jscript, we can thus have a reference to all the DOM objects that are passed to or used by a Javascript function.
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.
Every time a method or property is called to a DOM element by JavaScript, the call is actually made to our wrapper and then delegated to the real object. The wrapper can analyse the method in/out parameters and return value, looking for other IDispatch pointers that represent new DOM objects. If it finds a new IDispatch pointer not yet met, we know that this object will now be visible to the JavaScript code, and we need to build another wrapper and pass it to JavaScript in its place. In the end, every JavaScript function will access DOM objects only through these wrappers and the tool will have complete control over the script execution.












I tested this out immediately on one of my JavaScript-heavy applications. Looks like I am clean of memory leaks! :)
Giving credit where credit is due: Thank you jQuery for keeping things clean with IE, so I don’t have to worry about it.
Installed it and used it on the app I am working on and it crashed IE :)
Oh well …
I wouldn’t be so quick to trust it.
I have an example of a leak problem which this doesn’t recognize.
the only truly reliable method of finding leaks is repeating actions while looking at the Task Manager.
LOL microsoft making a memory leak detector
question is, why don’t they use it to fix the damn memory leaks?!?
This is awesome. Web developers are finally getting some tools for IE. This tool and IE web developer toolbar add on will help us combat one of the nastiest web browsers on the net today.
Now only if someone can port/clone Firebug to IE.
actually there already is something thats pretty close. i’ve been using it for a few weeks now, and i no longer dread debugging/troubleshooting in ie. i
http://www.debugbar.com/
http://www.my-debugbar.com/wiki/CompanionJS/HomePage
Has anyone faced an issue of leaks when using prototype.js and dojo.js in the same page ?
For this leaks like anything in IE 6 & 7 :( !!!
Thanks. Good article.
@Marc
I wouldn’t upgrade that jQuery if I were you. Those prats introduced lots of leaks in the new version(s). Third version of a third version (after three years) and they still can’t deal with IE6 (for several different reasons.)
Turns out (too late to help anyone) that, once again, jQuery has introduced complexity where it wasn’t needed (namespaced events?), causing cross-jQuery issues that make browser differences quite simple in comparison.
So give discredit where it is due. Aggravating known IE6 issues (known for 10 years and counting) in 2009 is not the hallmark of a great browser equalizer. The UI guy knew about this memory leak in 1.3x two months ago and did nothing but bump the milestone on a ticket for his side show. (!)
Suffice to say, don’t use jQuery and especially don’t use widgets built on top of a specific version of jQuery (the definition of “jQuery” changes from one month to the next.)