【问题标题】:Memory leaks in IE JS while XMLHTTP requestsXMLHTTP 请求时 IE JS 中的内存泄漏
【发布时间】:2010-09-04 16:22:14
【问题描述】:

每个 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>

【问题讨论】:

  • 您也需要支持 IE 6 吗?如果没有,为什么不使用本机 XMLHttpRequest 而不是使用 ActiveX 对象?也许这可以解决您的问题。
  • 2Mercel Korpel:我无法尝试使用 XMLHttpRequest,因为我收到一条错误消息“访问被拒绝”(跨域请求,因为此 HTML 基于本地计算机和位于 facebook 的 URL)。已进行所有防止此错误的设置,但内置 XMLHttpRequest 不起作用。

标签: javascript internet-explorer memory-leaks xmlhttprequest


【解决方案1】:
locHTTPRequest.onreadystatechange = ProcessPaymentHTTPRequest;

在本地 JScript 对象(ProcessPaymentHTTPRequest 函数,其范围内包含请求对象)和非 JScript 对象(XMLHttpRequest ActiveX 对象)之间创建一个引用循环。正是这种引用循环让IE无法GC。

delete locHTTPRequest["onreadystatechange"];

虽然这对于原生 JavaScript 对象来说是可以的,但实际上delete 实际上并不能从 DOM 对象中删除事件处理程序。所以处理程序和引用循环仍然存在。相反,通常做的是用哑值覆盖locHTTPRequest.onreadystatechange 处理程序,例如立即返回的预定义函数,或'',或null。或者,使用addEventListener/attachEvent 及其对应的remove-handler 方法。

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,这也是非标准的。如果您不想发送任何内容,而不是提供 null,请省略 data 参数。

【讨论】:

  • 我无法尝试使用本机 XMLHttpRequest,因为我收到一条错误消息“访问被拒绝”(跨域请求,因为此 HTML 基于本地计算机和位于 facebook 的 URL)。已进行所有防止此错误的设置,并且使用 activex 对象 XMLHttp 跨域工作,但使用内置 XMLHttpRequest 不起作用。
  • 我根据您的建议更改代码: 1. change delete locHTTPRequest["onreadystatechange"];到 locHTTPRequest.onreadystatechange = null; 2. 禁用 CollectGarbage(); 3.
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-05
  • 1970-01-01
  • 2018-01-11
  • 2012-04-24
相关资源
最近更新 更多