Welcome to MSDN Blogs Sign in | Join | Help

GPDE Team Blog

A blog about Microsoft's Global Product Development - Europe team, based in Dublin, Ireland.
JavaScript Memory Leak Detector

joinmicrosofteurope.comby Paolo Severini, from Microsoft's GPDE team in Europe (we're hiring)
© 2008 Microsoft


INTRODUCTION

[ introduction | installation | usage | heuristics | references ]

JavaScript Memory Leak Detector (download) is a debugging tool to detect memory leaks in JavaScript code. It can be installed as an Internet Explorer band and it is expressly designed to find memory leaks in JavaScript code that runs in Internet Explorer.

The tool is currently in beta and we welcome your feedback (email paolosev [at] microsoft [dot] com, or use the feedback form below).

Note: as reported by several user, the current version of the tool has a few issues with pages that contain frames. An updated version will be released soon.

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.

These memory leaks often occur as a result of circular references between JavaScript objects and objects within IE’s DOM (document object model).

Both the JavaScript engine and IE have independent memory management schemes. The JavaScript engine uses garbage collection to reclaim the memory allocated for JavaScript objects that are not used anymore.

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:

<html>
    <head>
        <script language="JScript">
         var jsObject;
         function SetupLeak()
         {
                jsObject = document.getElementById("LeakedDiv");
                document.getElementById("LeakedDiv").expandoProperty = jsObject;
         }
     </script>
    </head>
    <body onload="SetupLeak()">
        <div id="LeakedDiv"></div>
    </body>
</html>

Here the SetupLeak() function creates a circular reference like this:

The IE team has been working hard to solve the problem. With the initial versions of Internet Explorer 6 practically all circular references between Javascript and DOM objects caused a memory leak. Avoiding leaks was not an easy task even because there are language constructs, like JavaScript closures, that make particularly difficult to track down those circular references.

Internet Explorer 7 improved the situation by releasing all references to JavaScript objects attached to the DOM tree when IE navigates away from that page. This allows the JavaScript engine to garbage collect those JavaScript objects and recover that memory. Almost the same changes were also shipped with the latest security updates of IE6. So, the previous code does not actually leak anymore.

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:

LeakedDiv.parentElement.removeChild(LeakedDiv);

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.

 

 


 

INSTALLATION

[ introduction | installation | usage | heuristics | references ]

JavaScript Memory Leak Detector is an Internet Explorer Band. It works on Windows XP and Windows Vista, with Internet Explorer 7.

To install it:

  1. Download the installer and unpack it from the ZIP archive: download link
  2. Close all the running instances of Internet Explorer.
  3. Run the setup program jsleaksdetector.msi.
  4. 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.
  5. 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.

 

 

 


 

USAGE

[ introduction | installation | usage | heuristics | references ]

This band is composed of four windows:

  1. Document tree window
  2. Memory leaks window
  3. Call stack window
  4. Script window

Window #1: Document Tree

The leaks detector works intercepting the execution of JavaScript inside IE. The tree view at the left of the band contains a list of all the documents previously opened in the browser and, for each document shows all the script code that was loaded into a script engine.

Color Codes

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

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

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

A JavaScript memory leak is (almost) always caused by a circular reference from an IE DOM object and a JavaScript object. When a leak node is selected in the tree, this list shows a list of "attached" JavaScript objects whose circular reference could be the cause of the leak.

Window #3: Call Stack

Selecting one of the existing items in the previous Memory Leaks window causes a call stack to be dispayed in the Call Stack window. The call stack represents the state of the script at the moment when the JavaScript object was attached to the DOM object.

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:

  1. When a script node is selected in the Document tree, the Script window shows the script code.
  2. 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

[ introduction | installation | usage | heuristics | references ]

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:

This dialog allows the user to select one of three available heuristics to detect JavaScript leaks. To understand the difference between the three available options is useful to take a look at the internal workings of the tool.

How it works

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.

Detecting leaks

Now that we can intercept all the calls between the DOM and the JavaScript worlds, we are on the good path towards leak detection. We can choose between different strategies, which correspond to the three options in the settings dialog:

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).

In all the three cases we follow a heuristic approach. We don't know what IE will actually do when the page is unloaded and, as we have seen, the IE team is removing old leak patterns with every new version of the browser. Anyway, the list of leaks reported by the tool can be useful information to find potential leaks and to enforce best practices in JavaScript coding.

 

 


 

REFERENCES

[ introduction | installation | usage | heuristics | references ]

 


JavaScript Memory Leak Detector by Paolo Severini

© 2008 Microsoft

Posted: Thursday, January 24, 2008 7:30 AM by eurojobs

Comments

kentaromiura said:

doesn't Microsoft solved the memory leak issue?

( http://support.microsoft.com/kb/929874/ )

# January 25, 2008 9:58 AM

eurojobs said:

kentaromiura, you are right, Microsoft has released a fix that solves IE6 memory leaks issues in most cases.

However, it is still possible to have leaks in some rare cases, as explained here: http://ajaxian.com/archives/ies-memory-leak-fix-greatly-exaggerated.

# January 25, 2008 11:08 AM

Tim McCormack said:

Great plugin! I already found a leak on my company's website.

I'd like to note that Step 4 of the installation instructions was not accurate for my machine. (IE 7 from upgrade on Win XP SP2.) I found the menu item elsewhere: View > Explorer Bar > js memory leaks detector. Odd that it shows up there instead.

# January 25, 2008 4:57 PM

thinboy said:

good

# January 26, 2008 10:17 AM

Ian said:

Seams not to work in Vista x64, it only appears in IE x64, not the 32 bit IE, where it just gives a grey bar

# January 26, 2008 6:03 PM

Friso Vrolijken said:

I also have IE 7 on XP SP2, but can't find it anywhere, after installation. I'll try rebooting now :-(

# January 28, 2008 5:07 AM

Richard Quadling. said:

Got it working and it looks useful.

If the Call Stack window could give the script url and line number, that would be great.

With libraries like prototype, using closures is a common way to keep things together. Having a "JScript anonymous function" as the call stack doesn't help.

But, overall, VERY VERY promising!

Kind regards,

Richard Quadling.

# January 28, 2008 10:04 AM

aaron said:

I installed it but it doesn't show up anywhere. I've got the IE developer toolbar installed too. Wonder if that's the issue...

# January 28, 2008 10:34 AM

eurojobs said:

Tim, Friso,

I will look into these installation problems.

In all my tests on IE7/WinXP SP2 the plugin appears (after closing and restarting IE) both under Tools->Toolbar->Explorer Bar and under View->Explorer Bar. But evidently there must be problems in some cases.

Thanks for reporting this, we will post an update version soon!

# January 28, 2008 10:46 AM

eurojobs said:

Richard,

I will try to improve the Call Stack reporting. Unfortunately too many javascript functions are anonymous, indeed.

Thanks for the positive feedback!

# January 28, 2008 10:50 AM

eurojobs said:

aaron,

Yes, it should work along with the IE developer toolbar.

# January 28, 2008 10:55 AM

emichael said:

I am another person unable to find it after installing.  I have AdobePDF, Roboform and IEDevToolbar installed.  Any ideas?  Thanks.

# January 28, 2008 8:04 PM

Tisha said:

Hello!

Unfortunately, I also cannot find it anywhere after installation, I also use IE Developer Toolbar. I have XP SP2 and IE 6 running.

# January 29, 2008 4:47 AM

kentaromiura said:

I can confirm that It works along IE dev Toolbar, but you can use only one at time (you've to select the plugin you want)

# January 29, 2008 7:19 AM

eurojobs said:

Hi Tisha,

Unfortunately IE6 is not supported.

In general, if you can't find the new explorer bar after installing, the problem should be solved in all cases by a reboot. Of course we will fix this in the next version.

...still in beta, after all! :-)

# January 30, 2008 6:09 AM

Brian said:

When I installed this program, it didn't iappear in my list of explorer bars.  It turns out that this was because I selected "make this visible to everyone" during the installation process.  When I switched it to "make visible only to me" (in the installation process), it appeared.  I am pretty sure that this is because I am not a local admin on the machine in question (just a domain admin).  The installer didn't have sufficient permissions to write the correct registry keys to make the new bar appear.

I don't actually have the program working (when I open pages containing JavaScript, it causes IE7 to crash).  But... at least I am past the installation process.  

# January 30, 2008 6:00 PM

bugrain said:

Hi,

Ran a few of our pages with the tool running and all was looking good.

Found one instance where a leak was reported, but the display of the leak info. is not helpful.

It shows lots of entries in the Memory leaks and Call stack and whichever is selected, the JavaScript source always has the same piece of code highlighted - and that seems to have nothing to do with the leak - the highlighting is over an end of line.

I should add that the page uses the JavaScript framework Prototype with the Prototip extension (without Prototip it's fine!).

Is this likely to be a problem due to the way the framework extends JS objects, etc. and not possible to fix or something you might want to look in to. I have a very small test case that shows the problem that I can make available.

One other suggestion - the possibility to log the pages to a file. Currently, we cannot test end pages in our applications as these close the browser window so the output is lost.

Other than that, it looks promising in helping the 'feel good factor'.

# January 30, 2008 7:13 PM

eurojobs said:

Hi Brian,

Thanks for reporting this. I forgot to mention that the installation requires administrator privileges.

The crash is strange; I would like to investigate this. Does it happen with a particular page?

# January 31, 2008 8:32 AM

eurojobs said:

bugrain,

The idea of adding the possibility of logging on a text file is very interesting.

Regarding the problem with the display of leak info, it would be great if you could send me the failing test case; my address is at the beginning of the page.

Thanks for your help!

# January 31, 2008 8:41 AM

Rufus said:

The first time I installed it, I used the "Intall for everyone on the computer" option. Like a lot of other folks, I couldn't see the tool under the explorer bar menu.

So I tried uninstalling and installing again, this time with the "Only for me" option. That worked great.

# January 31, 2008 11:17 AM

ashish said:

It's really a gr8 tool. But i am not able to understand some points like ... why it is showing my JS functions as anonymous function. The functions are defined in my JS file which I have included at the top. Infact these functions are running fine without any problem. Can anyone tell me the reason, why these functions are marked as anonymous and how can i solve this issue.

Regards,

Ashish

# February 8, 2008 1:18 AM

eurojobs said:

Ashish,

Not knowing your code I cannot be sure, but I think that the problem could be this. If you have the following code:

   Test = function()

   {

       this.a = function(){ ...}

   }

   function b()

   {

       var t = new Test();

       t.a();

   }

Here the function b() has a name. But the function 'Test.a()' is actually anonymous, even though it is invoked by name, since the name "a" is just the name of the "data member" of Test associated to the function, not the name of the function itself. So, the JS debugging engine will show "anonymous function" as the function name in the call stack.

Code like this is quite frequent writing OO javascript code.

paolo

# February 8, 2008 12:30 PM

Megha said:

hi,

I have installed the JavaScript Memory Leak Detector successfully , but the moment I try ro run the detectoe , the IE crashes .This happens every time I try running the detector.

Pls help !!

# February 21, 2008 5:16 AM

eurojobs said:

Hi Megha,

I am aware that the first beta of the tool has some issues with pages with frames. I am working on the fix and a new version will be released soon.

Sorry for this...

paolo

# February 21, 2008 2:25 PM
New Comments to this post are disabled
Page view tracker