Утечки памяти в IE JS при запросах XMLHTTP - PullRequest
0 голосов
/ 04 сентября 2010

Каждый 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 Ответ

1 голос
/ 04 сентября 2010
locHTTPRequest.onreadystatechange = ProcessPaymentHTTPRequest;

Создает ссылочный цикл между объектом native-JScript (функция ProcessPaymentHTTPRequest, которая имеет объект запроса в области видимости) и объектом не-JScript (объект XMLHttpRequest ActiveX).Именно этот вид ссылочного цикла приводит к сбою IE в GC.

delete locHTTPRequest["onreadystatechange"];

В то время как это будет нормально для нативного объекта JavaScript, в действительности delete на самом деле не работает для удаления обработчика событий изобъект DOM.Таким образом, обработчик и цикл ссылок остаются на месте.Вместо этого обычно выполняется перезапись обработчика locHTTPRequest.onreadystatechange значением dud, например предопределенной функцией, которая немедленно возвращает значение, либо '', либо null.Или, в качестве альтернативы, используйте addEventListener / attachEvent и соответствующие им методы обработчика удаления.

CollectGarbage();

Что это делает?На самом деле вы мало что можете сделать, чтобы повлиять на GC от JS.

Помимо:

<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, так что просто используйте unversioned 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.

...