XMLHTTP请求时IE JS中的内存泄漏

时间:2010-09-04 16:22:15

标签: javascript internet-explorer memory-leaks xmlhttprequest

每个ProcessingPayments()都使用了内存增加。 CollectGarbage()没有帮助。使用Drip查看内存使用情况,但不要查看任何DOM泄漏。

我只使用IE8并在旧版本上进行测试。其他不感兴趣的浏览器。

如何在执行此脚本时减少不断增长的内存使用量?

<!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>

1 个答案:

答案 0 :(得分:1)

locHTTPRequest.onreadystatechange = ProcessPaymentHTTPRequest;

在native-JScript对象(具有范围内的请求对象的ProcessPaymentHTTPRequest函数)和非JScript对象(XMLHttpRequest ActiveX对象)之间创建引用循环。正是这种参考循环使IE无法通过GC。

delete locHTTPRequest["onreadystatechange"];

虽然对于本机JavaScript对象来说没问题,但实际上delete实际上并不能从DOM对象中删除事件处理程序。因此处理程序和引用循环保持不变。通常做的是使用dud值覆盖locHTTPRequest.onreadystatechange处理程序,例如立即返回的预定义函数,或''null。或者,使用addEventListener / attachEvent及其相应的删除处理程序方法。

CollectGarbage();

那是做什么的?你可以做很多事情来影响JS的GC。

除了:

<script language="JScript">

type="text/javascript"代替language。我知道你不关心非IE,但似乎没有任何不兼容和非标准的点。

 try { var locHTTPRequest = new ActiveXObject("MSXML2.XMLHTTP.6.0"); }
 catch (e) { var locHTTPRequest = new ActiveXObject("MSXML2.XMLHTTP"); }

没有必要这样做。您没有使用较新的MSXML版本的任何功能,因此对于未版本化的XMLHttp来说非常丰富。另外,首先选择native-JS XMLHttpRequest。不仅因为它存在于其他浏览器上,而且因为它更高效,并且作为原生JS,不会导致内存泄漏。

最佳:为IE6添加后备:

if (!window.XMLHttpRequest && 'ActiveXObject' in window) {
    window.XMLHttpRequest= function() {
        return new ActiveXObject('MSXML2.XMLHttp');
    }
}

然后在任何地方使用标准new XMLHttpRequest()

locHTTPRequest.send(null);

即使对于IE,这也是非标准的。如果您不想发送任何内容,请省略data参数,而不是提供null