Memory leaks in IE JS while XMLHTTP requests
Each ProcessingPayments() used memory increase. CollectGarbage() not helps. Use Drip to view memory usage, but don't view any DOM leaks.
I use only IE8 and tested on older versions. Other browsers not interested.
How can I decrease growing memory usage while execute this script?
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>JS IE XMLHTTP - Memory leaks</title>
</head>
<body onload="ProcessingPayments();locCollectGarbage();">
<script language="JScript">
var toProcessingPayments;
var ProcessingPaymentsPeriod = 1*60*1000;
var SessionCount = 1;
var CollectGarbageCount = 1;
function ProcessPayment(arrParams) {
var e;
var strURL = "http://www.facebook.com/";
var strURLParam = "";
try {开发者_开发知识库 var locHTTPRequest = new ActiveXObject("MSXML2.XMLHTTP.6.0"); }
catch (e) { var locHTTPRequest = new ActiveXObject("MSXML2.XMLHTTP"); }
function ProcessPaymentHTTPRequest() {
if (locHTTPRequest.readyState != 4) {
return;
}
if (locHTTPRequest.status != 200) {
document.getElementById("CurrentSession").innerHTML = document.getElementById("CurrentSession").innerHTML
+arrParams.i+" = error code "+locHTTPRequest.status+"<br />";
return false;
}
if (locHTTPRequest.getResponseHeader("Content-Type").indexOf("text/html") < 0) {
document.getElementById("CurrentSession").innerHTML = document.getElementById("CurrentSession").innerHTML
+arrParams.i+" = wrong content type "+locHTTPRequest.getResponseHeader("Content-Type").indexOf("text/html")+"<br />";
return false;
}
try {
document.getElementById("CurrentSession").innerHTML = document.getElementById("CurrentSession").innerHTML
+arrParams.i+" = processed<br />";
return true;
}
catch(e) {
if (locHTTPRequest.responseXML.parseError != 0) {
return false;
}
else {
return false;
}
}
locHTTPRequest.abort();
delete locHTTPRequest["onreadystatechange"];
locHTTPRequest = null;
} // function ProcessPaymentHTTPRequest()
strURLParam = "?"+arrParams.i;
locHTTPRequest.open("get", strURL+strURLParam);
document.getElementById("CurrentSession").innerHTML = document.getElementById("CurrentSession").innerHTML
+arrParams.i+" = request<br />";
locHTTPRequest.onreadystatechange = ProcessPaymentHTTPRequest;
locHTTPRequest.send(null);
}
function ProcessingPayments(arrPayment) {
var e;
toProcessingPayments = null;
document.getElementById("CurrentSession").innerHTML = "";
for (var i = 0; i < 10; i++) {
ProcessPayment({
i: i
});
}
SessionCount++;
document.getElementById("Session").innerText = SessionCount;
toProcessingPayments = setTimeout(ProcessingPayments, ProcessingPaymentsPeriod);
}
function locCollectGarbage() {
CollectGarbage();
document.getElementById("CollectGarbage").innerText = CollectGarbageCount;
CollectGarbageCount++;
setTimeout(locCollectGarbage, 5*60*1000);
}
</script>
</body>
<p>Sessions: <span id="Session">0</span></p>
<p>CollectGarbage(): <span id="CollectGarbage">0</span></p>
<hr />
<br />
<p>Current session:</p>
<p id="CurrentSession"></p>
</html>
locHTTPRequest.onreadystatechange = ProcessPaymentHTTPRequest;
Creates a reference loop between a native-JScript object (the ProcessPaymentHTTPRequest
function, which has the request object in scope) and a non-JScript object (the XMLHttpRequest
ActiveX object). It is this kind of reference loop that makes IE fail to GC.
delete locHTTPRequest["onreadystatechange"];
Whilst that would be OK for a native JavaScript object, in reality delete
doesn't actually work to remove an event handler from a DOM object. So the handler and reference loop remains in place. What is typically done instead is to overwrite the locHTTPRequest.onreadystatechange
handler with a dud value, such as a predefined function that immediately returns, or ''
, or null
. Or alternatively, use addEventListener
/attachEvent
and their corresponding remove-handler methods.
CollectGarbage();
What does that do? There's not really much you can do to influence GC from JS.
Aside:
<script language="JScript">
type="text/javascript"
instead of language
. I know you don't care about non-IE, but there seems little point in being gratuitous incompatible as well as non-standard.
try { var locHTTPRequest = new ActiveXObject("MSXML2.XMLHTTP.6.0"); }
catch (e) { var locHTTPRequest = new ActiveXObject("MSXML2.XMLHTTP"); }
There is no need to do this. You aren't using any features of the newer MSXML version, so just plump for unversioned XMLHttp
. Also, go for native-JS XMLHttpRequest
first. Not just because it exists on other browsers, but also because it's more efficient and, being native JS, doesn't cause memory leaks.
Best: add fallback for IE6:
if (!window.XMLHttpRequest && 'ActiveXObject' in window) {
window.XMLHttpRequest= function() {
return new ActiveXObject('MSXML2.XMLHttp');
}
}
and then just use standard new XMLHttpRequest()
everywhere.
locHTTPRequest.send(null);
This is non-standard even for IE. Omit the data argument if you don't want to send anything, rather than supplying null
.
精彩评论