Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

XMLHttpRequest and memory leak (onreadystatechange closure)

Status
Not open for further replies.

Chris303

Technical User
Sep 17, 2006
16
GB
The code is pasted here.


I basically have a custom object which contains a XMLHttpRequest object inside it.

Inside my object's declaration I have the following.

this.oXMLHttp.onreadystatechange = function()
{
self.handleReadyStateChange();
};

which is setting the onreadystatechange event to a prototype function within the object called handleReadyStateChange.

I am having to use this "self" hack so I can obtain a reference to the current object with "this" from inside handleReadyStateChange, which I have documented next.

AjaxObject.prototype.handleReadyStateChange = function()
{
/*
* Author: Chris Miles
* Name: handleReadyStatusChange
* Purpose: Called when the status of the XMLHttpRequest object's state changes.
* Params: none
* Returns: none
*/

if((this.oXMLHttp.readyState === XMLHTTP_INTERACTIVE))
{
this.bHasBeenInteractive = true;
}
if((this.oXMLHttp.readyState === XMLHTTP_COMPLETED))
{
if(this.bHasBeenInteractive === true)
{
this.fCallBack(this.oXMLHttp.responseText);
}
else
{
alert("request completed but, never went through the correct stages");
}
}
}

Now this code works perfectly save for the fact I am leaking memory with the closure at the top.

Is there another solution (cleaner hopefully), so when handleReadyStateChange is called it can access the current instance of the object it belongs to.

thanks

Chris
 
It sounds like a job for the Function object's "apply" method:


Try something like this:

Code:
this.oXMLHttp.onreadystatechange = this.handleReadyStateChange.apply(this);

or this:

Code:
this.oXMLHttp.onreadystatechange = WhatEverThisObjectsClassNameIs.handleReadyStateChange.apply(this);

When using the Prototype JS library, you can also use the "bind" method (see the weather / horoscopes callbacks in the JS code at for an example).

Hope this helps,
Dan

Coedit Limited - Delivering standards compliant, accessible web solutions

[tt]Dan's Page [blue]@[/blue] Code Couch
[/tt]
 
xwb... my firefox leak monitor extension monitors objects within the browser which are not being garbage collected after being done with.

my application is using thousands of XMLHttpRequests in a short amount of time, and the browser will not be shut down for a possible long amount of time, as the application is going to be run on a kiosk which will always be on, and possibly always in use.

I can do a simple demo of creating and using lots of my own object and simply watch the task manager memory graph to see memory being used up and up and up and not beeing freed.

billy ray, thanks, I will try that out today.
 
this.oXMLHttp.onreadystatechange = this.handleReadyStateChange.apply(this);

reports a type mismatch.

this.oXMLHttp.onreadystatechange = AjaxObject.handleReadyStateChange.apply(this);

reports null or not an object.

thanks
 
As I've been working today, I'm being lazy, and so have copied this code direct from the Prototype JS library instead of massaging it into something a bit more cut down However, it should suit you well if you're doing a lot of Ajaxy stuff.

Add this as 'common' code somewhere:

Code:
var $A = function(iterable) {
	if (!iterable) return [];
	if (iterable.toArray) {
		return iterable.toArray();
	} else {
		var results = [];
		for (var i = 0, length = iterable.length; i < length; i++) results.push(iterable[i]);
		return results;
	}
}

Function.prototype.bind = function() {
	var __method = this, args = $A(arguments), object = args.shift();
	return function() {
		return __method.apply(object, args.concat($A(arguments)));
	}
}

and then you should be able to use this:

Code:
this.oXMLHttp.onreadystatechange = this.handleReadyStateChange.bind(this);

Hope this helps,
Dan

Coedit Limited - Delivering standards compliant, accessible web solutions

[tt]Dan's Page [blue]@[/blue] Code Couch
[/tt]
 
Hi. Thanks.

The firefox leak monitor extension still detects a leak with the bind function unfortunately.
 
I did a quick search on Google for "firefox leak monitor prototype bind", and found this interesting blog entry:


Wrong Notes said:
Prototype will install a listener on the unload event and cleanup all listeners registered through Event.observe(). But, reading the fine print it only does this if you're in IE! But, I'm seeing tons of memory leaked in Firefox. Why not do it for Firefox as well? It's all the same javascript, and if I have to go around and manage all of the listeners myself what's the point of having IE then do it for me? Only the Prototype developers know why. But, here is what I did to fix my problems:


Code:
Event.observe( document, 'unload', Event.unloadCache );


Put that in my javascript and viola I went from over 70-80 leaked objects down to 2. I'm so smart...hey wait a minute two! So I checked my leak monitor tool, and it's coming from the bind() method in prototype. Well I'm a heavy user of the bind() method so it could be anywhere. At first I thought maybe it was Behaviour so I removed Behaviour, but nope still 2 being leaked.

Wow... I had no idea, and we use bind() extensively at work... I'll be doing some work on this tomorrow, I can see.

Hope this helps (it certainly has helped me!),

Dan

Coedit Limited - Delivering standards compliant, accessible web solutions

[tt]Dan's Page [blue]@[/blue] Code Couch
[/tt]
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top