talideon.com

Blackout Ireland

March 15, 2005 at 11:00PM Fixing JavaScript memory leaks for good.

I’m a fan of unobtrusive JavaScript and I’ve strove to make my JavaScript code as unobtrusive as possible for years now.

However, I discovered something about IE a while ago when I was reading through the comp.lang.JavaScript FAQ: IE leaks memory like a sieve when you use closures with any kind of COM object (including DOM elements, which are implemented using COM). That kinda sucks. Firefox and other browsers apparently have the same problem only to a lesser extent. Damned multiple garbage collectors!

I’ve run into the whole memory leak problem before, but it never occurred to me that was the cause. But last weekend, I decided to fix it once and for all.

So I present to you my very own all-singing, all-dancing EventManager!

/*
 * EventManager.js
 * by Keith Gaughan
 *
 * This allows event handlers to be registered unobtrusively, and cleans
 * them up on unload to prevent memory leaks.
 *
 * Copyright (c) Keith Gaughan, 2005.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Common Public License v1.0
 * (CPL) which accompanies this distribution, and is available at
 * http://www.opensource.org/licenses/cpl.php
 *
 * This software is covered by a modified version of the Common Public License
 * (CPL), where Keith Gaughan is the Agreement Steward, and the licensing
 * agreement is covered by the laws of the Republic of Ireland.
 */

// For implementations that don't include the push() methods for arrays.
if (!Array.prototype.push) {
    Array.prototype.push = function(elem) {
        this[this.length] = elem;
    }
}

var EventManager = {
    _registry: null,

    Initialise: function() {
        if (this._registry == null) {
            this._registry = [];

            // Register the cleanup handler on page unload.
            EventManager.Add(window, "unload", this.CleanUp);
        }
    },

    /**
     * Registers an event and handler with the manager.
     *
     * @param  obj         Object handler will be attached to.
     * @param  type        Name of event handler responds to.
     * @param  fn          Handler function.
     * @param  useCapture  Use event capture. False by default.
     *                     If you don't understand this, ignore it.
     *
     * @return True if handler registered, else false.
     */
    Add: function(obj, type, fn, useCapture) {
        this.Initialise();

        // If a string was passed in, it's an id.
        if (typeof obj == "string") {
            obj = document.getElementById(obj);
        }
        if (obj == null || fn == null) {
            return false;
        }

        // Mozilla/W3C listeners?
        if (obj.addEventListener) {
            obj.addEventListener(type, fn, useCapture);
            this._registry.push({obj: obj, type: type, fn: fn, useCapture: useCapture});
            return true;
        }

        // IE-style listeners?
        if (obj.attachEvent && obj.attachEvent("on" + type, fn)) {
            this._registry.push({obj: obj, type: type, fn: fn, useCapture: false});
            return true;
        }

        return false;
    },

    /**
     * Cleans up all the registered event handlers.
     */
    CleanUp: function() {
        for (var i = 0; i < EventManager._registry.length; i++) {
            with (EventManager._registry[i]) {
                // Mozilla/W3C listeners?
                if (obj.removeEventListener) {
                    obj.removeEventListener(type, fn, useCapture);
                }
                // IE-style listeners?
                else if (obj.detachEvent) {
                    obj.detachEvent("on" + type, fn);
                }
            }
        }

        // Kill off the registry itself to get rid of the last remaining
        // references.
        EventManager._registry = null;
    }
};

Download EventManager.js, and be happy.

Update (2005-06-07): I put the updated version that supports event capture and fixes the bug where it wasn’t deregistering handlers in browsers that support addEventHandler() and removeEventListener(). Those who want this code to work on older browsers should peruse this blog entry.

Update (2007-10-25): It’s over two years since I wrote this, and I’m pretty sure I can do a much better job of it. I think I’ll hack on the code and post something up tomorrow.

Comments

1 On March 16, 2005 at 1:04, Chris Heilmann wrote:

Will give it a spin, this might be an add-on to the unobtrusive course [smile]

2 On March 16, 2005 at 1:47, Keith wrote:

That would indeed be pretty cool!

As an aside, I mentioned EventManager in response to a post on memory leakage on Aaron Boodman’s site. He informed me of Mark Wubben’s EventCache, which implements a similar idea (though his code doesn’t hide registration too). So don’t forget to pass the love around. [smile]

3 On March 17, 2005 at 15:22, Mark Wubben wrote:

Okay, when I found this in my referers, and saw the code, I was like ‘Whaaat?????’. But luckily it was just the same idea implemented in virtually the same way [smile] That’s what you get with simple concepts!

4 On March 20, 2005 at 19:50, Tom Wright wrote:

Cheers for pointing this page out to me Keith, a nice solution. Had been working on a similar caching concept but now you and Mark have saved me the time [smile]

One small point: typo in the IE DOM. Should read obj.detachEvent. On first test drive IE still seemed to be leaking until I realised that!

5 On March 21, 2005 at 13:22, Keith wrote:

You’re indeed correct! Fixed that. Strange though: why didn’t IE throw an error when I was testing it..? Ah yes, the if statement! Oh well!

6 On April 13, 2005 at 8:58, Revence 27 wrote:

Keith, you are one of the best codists I ever crossed. At least with this. You rock.

7 On April 13, 2005 at 22:11, Keith wrote:

Flattery will get you everywhere. [smile]

8 On April 19, 2005 at 21:56, Pablo wrote:

Hi,

Can someone post an example of use of this code (EventManager.js). I’m a newbie with a events but needs a crossbrowser solution and found this and looks great.

Thanks in advance.

btw ... I have tried with this:

<html>
<head>
<script type=text/javascript src=EventManager.js></script>
<script type=text/javascript>
    function onLoad() {

    EventManager.Add(document.getElementById(testCase),click,hit );
    return true;
    }

    function hit(evt) {
        alert(click);
    }
</script>
</head>

<body onload='javascript: onLoad();'>

<div id='testCase' style='width:100%; height: 100%; background-color: yellow;'>
  <h1>Click me!</h1>
</div>

</body>
</html>

9 On April 20, 2005 at 16:55, Keith wrote:

On first view, your code looks reasonable. However, I’ll need to take a short while out to review it properly. The good news is that I’m going to be writing up some blog entries shortly demonstrating its use and the use of a few other bits and pieces I’ve posted up on the site.

Stay tuned...

10 On May 5, 2005 at 18:16, JohnO wrote:

Keith,

I love the code (I liked it so much, I stole the idea, and wrote an AjaxManager (for XMLHTTPRequest calls)). I’ve since been using it, however have come across one problem.

I want to use this for form validation. Obviously:

EventManager.Add(forms[i], "submit", formSubmitted);

will attach the handler just fine. BUT! if I return false in my formSubmitted function, the form doesn’t care, it submits anyway, bummer.

this is because, back in the olden days, you had to do this:

<form onSubmit="return formSubmitted()">

that extra return there does all the magic. So how do we replicate that into the EventManager line???

Anyone?

11 On May 5, 2005 at 18:46, Keith wrote:

I think what you’re looking for is something to cancel the event. I have something lying about there, but I’ll need to take a look about for it here...

12 On May 5, 2005 at 20:20, JohnO wrote:

Aha... Well, I’m one step closer, and you wouldn’t believe me if I told you it works in IE, and not in Firefox...

formSubmitted obviously takes in an event parameter. Supposedly:

evt.cancelBubble = true;

will cancel the event, so it won’t bubble up to the form element... however, in either IE nor firefox will it work. You can also set this property:

evt.returnValue=false;

That will stop the bubbling in IE, not Firefox...

I’m also aware that this:

evt.stopPropagation();

should stop the event in firefox, but sadly doesn’t.

So, it remains to be seen how I can stop the bubbling in firefox.. I’m on a quest...

13 On May 5, 2005 at 21:06, JohnO wrote:

Uhoh,

I don’t think this is good news...

Event.stopPropagation()

Excerpt:

The stopPropagation method is used prevent further propagation of an event during event flow. If this method is called by any EventListener the event will cease propagating through the tree. The event will complete dispatch to all listeners on the current EventTarget before event flow stops. This method may be used during any stage of event flow.

It appears we can’t stop it from happening, unfortunately. That is, if I’m reading the spec correctly. It will cease propagating through the tree, BUT, will complete dispatch to the current target (which is the form). Therefore, as far as I understand, all listeners to the submit event on the form will fire, which includes submitting the form element.

I am most sad. In any case, I’ve submitted a bug report to Mozilla (bug# 293048)

14 On May 5, 2005 at 22:59, JohnO wrote:

Wonderful,

I’ve just checked my email, where the Mozilla team has responded to my bug report. They say this:

Event.preventDefault()

Will prevent the default action from firing. As I’ve left the office, I am unable to test it, but I will let you all know tomorrow...

15 On May 6, 2005 at 14:52, JohnO wrote:

It does work! I just wish I could have found it sooner, geez...

16 On May 21, 2005 at 19:36, Sascha wrote:

I do wonder why you are passing true as useCaption parameter to addEventListener and false to removeEventListener.

As a matter of fact, the removeEventListener call will do nothing, because the parameters do not match those which were used during registration.

17 On June 1, 2005 at 13:46, Phil wrote:

Heh. Have been using an event manager code struct very like this one (think I nabbed it from Erik Arvidsson or peterned) for a while now. It also works if the client only understands obj['on'+type] (like IE Mac, earlier Opera versions, NN4.x etc., in other words, the browsers the client is bound to be using!)

In any case, extending the object pushed to the _registry array to include the capture Boolean and using that in the removeEventListener call will sort out discrepancies like Sascha pointed out. Just be sure you have a Boolean for capture before pushing:

Add:function(obj, type, fn, cap){
    if(typeof cap!='boolean'){cap=new Boolean(false);}
    .
    .
    obj.addEventListener(type, fn, cap);
    this._registry.push( {obj:obj, type:type, fn:fn, cap:cap} );
}
CleanUp:function(){
    .
    .
    obj.removeEventListener(type, fn, cap);
}

18 On June 2, 2005 at 15:31, Keith wrote:

I’d code in an older version of the event handler that I never gave to anybody that did just that. I pulled it out because I felt it bloated the code too much, and I don’t see the likes of NN4 as being worth supporting these days, especially due to their lack of CSS support, which makes things difficult to do without resorting to tag soup.

I’d already made the fixes Sasha suggested to my own version before he suggested them. Mind you, because of work pressure I haven’t had the time to upload the modified version. However, in practice FF architecture is such that the memory leakage is far less severe than IE.

I’ll upload my most recent version as soon as I get a free moment.

19 On June 3, 2005 at 22:39, Moshe wrote:

Thanks for this page :)

I have many existing large sites that heavily use javascript and going thru all of them and change to work with this script was unacceptable, so i’ve made this script: ( maybe lame but seems to work :)

<script>
function release_events() {
  var events = new Array('onfocus','onblur','onchange',
'onclick','onmousedown','onmouseup','onmouseover',
'onkeypress','onkeydown','onkeyup','onkeypress');
	var ie = document.detachEvent ? 1 : 0;
	release_events_recursive(document, events, ie);
}

function release_events_recursive(parent, events, ie) {
	var i;
  for (i=0; i<events.length; i++) if (parent[events[i]]) {
		if (ie) parent.detachEvent(events[i], null);
else parent.removeEventListener(events[i], null, false);
	}
  for (i=0; i<parent.childNodes.length; i++)
release_events_recursive(parent.childNodes[i], events, ie);
}
</script>

Then i put in <body> onunload=releaseevents() I’ve listed events only that i use most of the time. Any comments? Thanks :)

20 On June 7, 2005 at 23:16, Keith wrote:

I’m rather skeptical, Moshe. I doubt that passing null as the function to detachEvent() and removeEventListener() will do exactly what you want.

I’d advise you to take a look at Drip, which will tell you where your JavaScript is leaking memory. It’s IE-specific, but useful generally anyway. You’ll probably be surprised by what you find.

If you’re not adding the handlers using the attachEvent() or addEventListener() methods, and instead doing something like obj.onwhatever = handler, then I’d say the following code would be better:

// I'm sticking closely to your code.
function ReleaseEvents() {
    var events = ["focus", "blur", "change", "click", "mousedown",
                  "mouseup", "mouseover", "keypress", "keydown",
                  "keyup", "keypress"];

    var helper = function(obj) {
        var i;
        for (i = 0; i < events.length; i++) {
            obj["on" + events[i]] = null;
        }
        for (i = 0; i < parent.childNodes.length; i++) {
            helper(parent.childNodes[i]);
        }
    }

    helper(document);
}

21 On June 13, 2005 at 23:34, Anjan Bacchu wrote:

I’ll upload my most recent version as soon as I get a free moment.

Did you get any free time - I’m having JavaScript/XmlHttpRequest related leaks and I’m trying to figure out what could be going wrong.

Thank you, ~A

22 On June 13, 2005 at 23:39, Anjan Bacchu wrote:

Hi Keith,

Thank you.

On April 20th, you commented “The good news is that I’m going to be writing up some blog entries shortly demonstrating its use and the use of a few other bits and pieces I’ve posted up on the site.”

Do you have some writeup available?

Thank you,

BR, ~A

23 On June 14, 2005 at 16:36, Keith wrote:

Did you get any free time.

If your reread the entry, you’ll see an update stating that the updates were uploaded last week on the seventh.

Do you have some writeup available?

Not yet. Time is at a premium for me right now so I don’t get to work on private stuff like that all that much.

24 On July 18, 2005 at 12:17, Jo wrote:

Possible this EventManager.js wont work on IE5.x MAC.

25 On July 26, 2005 at 12:48, Mark wrote:

Yo Keith, I’ve tried to improve your Event Manager so it complies with the JSLint Javascript Verifier and this is what I came up with. (JSLint says its ok)

Changes are...

  • Line 26: Needs a ;
  • Line 35: Should be === when comparing with null
  • Line 60-63: Rearranged using brackets and on line 35
  • Line 90: Replaced i++ with i=i+1
  • Line 92: Replaced with construct, used a var instead
  • Line 92: Rearranged using brackets

Code redacted by editor.

26 On July 27, 2005 at 12:25, Keith wrote:

Thanks Mark.

Code formatting is currently something I do by hand. The site’s currently running on ColdFusion 5, which has an awful regex engine. I hope to be moving to a server with ColdFusion MX soon. Until then, no code formatting. [sad]

I’ll deal with each one of the changes in turn:

Line 26: Needs a ;

Where I’m assigning a function to a variable, I tend to avoid adding trailing semicolons. I used to do so, but I’m uncomfortable with it. No worries though, I don’t mind the change.

Line 35: Should be === when comparing with null

I knew about that, but didn’t think it was widespread. If it is, all the better! I’ll make this change.

Line 60-63: Rearranged using brackets and on line 35

I’ve started to force myself to do this anyway. I’ll update the code to reflect this.

Line 90: Replaced i++ with i=i+1

Ah, here’s where I disagree with Doug. i++ is only tricky when it’s used as part of a larger expression. I only us it sparingly and then only as an incrementer in loops. I’ll change it to ++i so jslint doesn’t crap out on the expression. That said, I still think i++ is just fine as it is.

Line 92: Replaced ‘with’ construct, used a var instead

I originally used a variable, but switched it to using with as it made the intention a little clearer in the context. I’ve no problems about changing it back, mind you.

If you don’t mind, I’ll fiddle with your comments above to fix the formatting. The simplest way would be for me to clip the code and leave the change notes. Do you mind? Note: The comments from Mark have been redacted slightly with his permission. He attempted to post up a revised version of EventManager. I’ve removed it, but left the notes he made of the changes in question. He also asked how to post up code in comments, which at present isn’t possible.

27 On August 2, 2005 at 13:09, John Parker wrote:

Does anyone know where I can download the Drip program mentioned in comment On June 7, 2005 at 11:16PM, Keith wrote?

The link http://jgwebber.blogspot.com/2005/05/drip-ie-leak-detector.html no longer works.

28 On August 5, 2005 at 2:03, Keith wrote:

I’d a look around myself for it recently, and it appears to have disappeared. I don’t have a copy locally either. [plain]

29 On August 11, 2005 at 2:37, OutOfHanwell.com wrote:

John Parker and Keith, Drip 0.2 can be downloaded from: http://www.outofhanwell.com/ieleak/

30 On August 11, 2005 at 13:43, Plop wrote:

Arent you missing the obj from the CleanUp???

CleanUp: function(){

should be

CleanUp: function(obj){

well the firefox console seems to think so.

31 On August 11, 2005 at 21:10, Ken Chapman wrote:

I don’t think your code ‘fixes JavaScript memory leaks for good’. It appears to me there is a far bigger issue. On Windows 2000, I have an HTML file that refeshes itself periodically. If the page has no JavaScripts, over time the Web browser does not appear to grow in its memory use. However, if I include even the simplist of JavaScripts, each refresh eats some memory. Sometimes some of it gets reclaimed (I assume through garbage collection), but over time the browser consumes more and more memory. The problem is really bad with IE, but even Firefox suffers to a much lesser degree from this. (I have not tested other browsers or browsers on platforms other than Windows 2000.)

Nonetheless, it is an issue for a tool we are working on to monitor our products at customer sites, since we don’t know what browser and on what platform a customer might choose to run the monitor. At least with the browsers I tested, the monitor eventually run out of memory and hang, which will not make our customer very happy. :^(

While I admire your effort to solve a particular type leak, does anyone know of anything that we can do about this very basic problem?

32 On August 16, 2005 at 23:32, Keith wrote:

@Ken: unless I could see the code, I’ve no idea what could be causing the problem. If you use EventManager rigourously you’ll prevent a class of problems that are the primary cause of memory leaks in JavaScript. However, it won’t necessarily get rid of them all, and those that are left are ones you ought to be taking care of in your own code anyway.

For instance, are you creating objects and holding onto them for longer than they’re needed? This applies to native JavaScript objects, DOM nodes, and the likes of COM objects.

The best I can say it try using the likes of Drip, as mentioned above, and if you are using EventManager, make sure you’re using the most recent version. There was a nasty bug in any versions up before early May that prevented memory from being deallocated.

@Plop: That’s an event object that it’s being passed, and it’s not essential to it working correctly. I haven’t been able to get Firefox to complain, but if it is, it’s only giving a warning and warnings don’t prevent script execution.

I’m really surprised that this entry is still getting comments! Not in a bad way, mind you. [smile]

33 On August 24, 2005 at 12:22, Norbert Szabo wrote:

Hello!

This code isn’t working. My page (refreshes periodically) doesn’t use closures, and still grows up in memory. I cant use Firefox, only IE. Anyone knows a working solution? I tried everything, but failed. Plz!

34 On August 24, 2005 at 16:07, Keith wrote:

@Norbert: Read what I wrote in reply to Ken. Without seeing the code in question that uses it, it’s impossible to see what exactly is causing the leaks.

And I doubt EventManager isn’t working. I and others have been using it for months now without the slightest problem.

And you are using closures each time you create a function in JS. They’re unavoidable. A closure is a function and any accompanying state at the time of its creation. If you have functions that reference variables outside of it, such as global variables, you have a closure.

You might not realise this, but even when you do <code>onclick=”blah()”</code> in HTML, you’re assigning an object (in this case the function <code>function() blah() </code>) on the JavaScript heap to, if you’re using IE, some reference counted COM object, causing a memory leak.

The point of EventManager is that you stop using this kind of even handler completely. I’m afraid without seeing the code, all I can so is tell you what I’ve told you and tell you to look at Drip to see where it’s leaking memory.

35 On August 24, 2005 at 18:02, Norbert Szabo wrote:

You’re inadvertently managing to tangle the JavaScript garbage collector (the functions you’re creating without realising it when you assign stuff to the onmouseover, onmouseout, and onclick event handlers) with reference-counted COM objects (the DOM element representing the div), though I can’t see why in this case they shouldn’t manage to untangle themselves anyway. Given the code you’ve given me, here’s how I’d rewrite that bit of HTML:

<div id="aa">...</div>

And using EventManager, I’d change your JavaScript to:

EventManager.add("aa", "mouseover", lilbox_in);
EventManager.add("aa", "mouseout", lilbox_out);
EventManager.add("aa", "click", function()
{
    redirectTo(11111);
});

/**
 * Shorthand for document.getElementById().
 */
function $(id)
{
    return document.getElementById(id);
}

/**
 * Extracts the target element for an event in a platform
 * independent way.
 */
function getEventTarget(evt)
{
    return evt.target || evt.sourceElement;
}

function lilbox_in(evt)
{
    // Get the event object in a cross-platform manner.
    evt = evt || window.event;

    // Which element triggered the event?
    var target = getEventTarget(evt);

    $(target.id + "up").style.background   = ...;
    $(target.id + "down").style.background = ...;

    target.style.cursor = "hand";
}

function lilbox_out(evt)
{
    // Get the event object in a cross-platform manner.
    evt = evt || window.event;

    // Which element triggered the event?
    var target = getEventTarget(evt);

    $(target.id + "up").style.background   = ...;
    $(target.id + "down").style.background = ...;

    target.style.cursor = "default";
}

function redirectTo(n)
{
    // Is this a reference to a frame or something?
    parent.center.src = "controller?id=" + n;
}

There’s more still that can be done with it on top of that, but that should be enough to get you started.

36 On August 25, 2005 at 20:34, Keith wrote:

You’re inadvertently managing to tangle the JavaScript garbage collector (the functions you’re creating without realising it when you assign stuff to the onmouseover, onmouseout, and onclick event handlers) with reference-counted COM objects (the DOM element representing the div), though I can’t see why in this case they shouldn’t manage to untangle themselves anyway. Given the code you’ve given me, here’s how I’d rewrite that bit of HTML:

<pre> &lt;div id=&quot;aa&quot;&gt;...&lt;/div&gt; </pre>

And using EventManager, I’d change your JavaScript to:

<pre> EventManager.add(&quot;aa&quot;, &quot;mouseover&quot;, lilboxin); EventManager.add(&quot;aa&quot;, &quot;mouseout&quot;, lilboxout); EventManager.add(&quot;aa&quot;, &quot;click&quot;, function() redirectTo(11111); );

/ Shorthand for document.getElementById(). / function $(id) return document.getElementById(id);

/ Extracts the target element for an event in a platform independent way. / function getEventTarget(evt) return evt.target || evt.sourceElement;

function lilboxin(evt) // Get the event object in a cross-platform manner. evt = evt || window.event;

// Which element triggered the event? var target = getEventTarget(evt);

$(target.id + &quot;up&quot;).style.background = ...; $(target.id + &quot;down&quot;).style.background = ...;

target.style.cursor = &quot;hand&quot;; }

function lilboxout(evt) // Get the event object in a cross-platform manner. evt = evt || window.event;

// Which element triggered the event? var target = getEventTarget(evt);

$(target.id + &quot;up&quot;).style.background = ...; $(target.id + &quot;down&quot;).style.background = ...;

target.style.cursor = &quot;default&quot;; }

function redirectTo(n) // Is this a reference to a frame or something? parent.center.src = &quot;controller?id=&quot; + n; </pre>

There’s more still that can be done with it on top of that, but that should be enough to get you started.

37 On August 25, 2005 at 20:42, Keith wrote:

Aside: I haven’t tested that, so it might be broken. Also, the events can only be registered on object once they’ve loaded, so the code will have to be executed when the page is completely loaded or just after the the part of the page with the elements you want to hook onto is loaded.

I really, really need to do a practical demonstration of how to use EventManager.

38 On August 28, 2005 at 19:36, Norbert Szabo wrote:

Keith. You helped me a lot! Thank you very much! (I think you’re right, a detailed demo would be awesome to everyone who wants to use your great solution)

39 On February 24, 2006 at 16:22, sinha wrote:

I have a situation. I have a foucs on a field and it has onblur event. When the user presses any key, Onblur event fires first and then keydown event fires. Based on some logic in function x() called by onblur event, I want to cancel the key down event. Any help is appreciated

Thanks, Sinha

40 On February 26, 2006 at 1:09, Keith wrote:

Sinha, this isn’t really the place to be making queries like that. You really ought to be looking for some public forum to ask questions like that.

However, this time around, I’ll answer your query. If you’re asking what I think you’re asking, it isn’t really possible. The best you can do is have some variable shared between the onblur and onkeydown handlers called, say, onBlurFired. Initially, this would be false, but when the onblur even is triggered, your handler would set it to true. Then the onkeydown event occurs, it could check the value of this to see whether or not it should handle it, and reset it to false.

Without a link to some code, I can’t really do better than that.

41 On February 27, 2006 at 21:13, sinha wrote:

Keith, Sorry for posting year. Thanks for your reply. I have so many fields on multiple screens. All of them have a onblur and each executes it’s own validation functions. Putting a flag would be lot of work. If we don’t have any other solution, I will have to go with it.

Thanks for your help, Sinha

42 On February 28, 2006 at 14:22, Keith wrote:

‘Sok. It’s just that I don’t like when the comments attached to posts get off-topic, though I do tolerate it. I’m sorry I couldn’t help any more.

Even if you’ve got a lot of them, the one flag should do. Though there’s the slim potential for a race condition, it’s not all that great. Also, you could figure out which elements the event was thrown on from the event object, and that could help. Also, you could use closures to wrap your event handlers with code to take care of the mechanics of ignoring the unwanted events.

43 On April 6, 2006 at 7:36, Rinesh Kumar wrote:

Hi,

I was trying to use the script. Well I could not determine how to use it. Can u please give some idea of how to use it.

Regards, Rinesh.

44 On April 20, 2006 at 23:26, Chetan Patil wrote:

One way to avoid leaks is to hide local vars and arguments from the closure:

function foo () {

   this.div = document.createElement(div);
   this.div.onclick = function() { alert(this.innerHTML); };
   this.div.innerHTML = Hello  + arguments[0];
   document.body.appendChild(this.div);
}

for (var i = 1; i < 5000; i++) {
   foo(i);
}

Here this.div and arguments[0] are hidden from the closure and the closure doesn’t store a reference to them.

Simple enough :)

45 On April 21, 2006 at 20:10, Keith wrote:

Chetan, there’s a problem with that: if there’s no variables to be closed over, you don’t have a closure, just a function reference. What you have above isn’t a closure at all.

46 On April 21, 2006 at 22:45, Chetan Patil wrote:

You are right, it is not a closure at all. I was referring to accidental leaks in cases like above, where one doesn’t want to use a closure but just a function reference. A function definition like above would end up acting as a closure on locally declared variables and arguments. In such cases, one has to remember to set the locally declared variables to null to allow them to be garbage collected. Or you could let them be garbage collected on page unload (by setting the dom eventHandlers to null) but till then they are unnecessarily using up browser memory.

47 On May 2, 2006 at 2:10, Paolo wrote:

Just wondering if you’ve gotten around to writing an implimentation tutorial for your script yet. I’ve been programming for about four years now, but know next to nothing about JS memory leaks (and not a whole lot of JS itself for that matter. I’ve always found it kinda fincky...but that might just because I don’t know it well enough. I usually use PHP or java or c++).

If you have the time i’d love it if you’d help me fix the leak on my site (though if you’re too busy i’d certainly understand). The site is rather simple, but i can’t for the life of me figure out how to fix the memory leak (e.g. how to properly impliment your script).

The site is located at http://gaiabot.awardspace.com. The index.html is just a frame set, which contains three frames (though only two of them are probably relavent to this). Those two are http://gaiabot.awardspace.com/main.html and http://gaiabot.awardspace.com/script.php.

If you have the time to help me I’d be ssooo much aperciated.

Thanks, --Paolo

48 On May 2, 2006 at 3:03, Paolo wrote:

Wow, complete brain fart. Can’t exactly read the source code of a php file from the (running) page itself.

Please check out the source of http://gaiabot.awardspace.com/script2.txt instead of script.php.

This is really a rather simplistic site, I just can’t seem to find (or atleast reconize) what is causing it to leak like crazy.

Thanks again, --Paolo

49 On July 5, 2006 at 11:25, Jeremy Leppan wrote:

I would like to know how to use this script - is there a beginners guide somewhere - or would someone mind emilaing me with a simple way to implement.

mjleppan@hotmail.com

thanks Jeremy

50 On July 14, 2006 at 14:45, pao aek wrote:

Hello

I would like to know too hw I can use the script.

Thank you

51 On May 23, 2007 at 15:55, David Merrilees wrote:

This is a nice idea, except it will remove any onunload events added through the api before they have a chance to fire.

52 On August 5, 2007 at 8:09, michael wrote:

Maybe the only correct way to use innerHTML - LEAK FREE http://www.posos.com/page/Index.cfm?SelNavID=2714. Use outerHTML...

53 On July 29, 2008 at 11:18, Adam Cox wrote:

What good tools are there to detect memory leaks in FireFox?

54 On July 29, 2008 at 13:09, Keith wrote:

Not that I know of, Adam.

55 On October 15, 2008 at 11:26, Phil Newby wrote:

I have a website and a particular page is leaking memory like mad. I hope your code will help. i think the naughty bit is in here...

<script language=”JavaScript”><!-- //this function calls a php generated js file function attachfile( pscripturl ) // create script, set relative URL, and load script = document.createElement( ‘script’ ); script.src = pscripturl; document.getElementsByTagName( ‘head’ )[0].appendChild( script ); //change backround colour of checkboxes by ID function setBG(checkboxID) checkbox = document.getElementById(checkboxID); if(checkbox.checked)= ‘#0f0’; else= ‘#f00’; //--> </script>

What do i need to add to make your script work on mine? I’m not a JS programmer and haven’t a clue.

Cheers phil

56 On October 16, 2008 at 8:29, Phil Newby wrote:

Sorry that code got scrambled - here it is again...

<script language=”JavaScript”> function attachfile( pscripturl ) = document.createElement( ‘script’ ); script.src = pscripturl; document.getElementsByTagName( ‘head’ )[0].appendChild( script );

function setBG(checkboxID) checkbox = document.getElementById(checkboxID); if(checkbox.checked)= ‘#0f0’; else= ‘#f00’; </script>

I hope that displays better!

57 On October 16, 2008 at 8:32, Phil Newby wrote:

Sorry i’m just making a mess here...

Here’s a link to it in a txt file... http://www.haroldstreet.org.uk/examplescript.txt