2010-03-11 4 views
40

Я создал веб-страницу, которая делает вызов Ajax каждую секунду. В Internet Explorer 7 он плохо теряет память (20 МБ за 15 минут).Простой jQuery Ajax вызов утечки памяти в Internet Explorer

Программа очень проста. Он просто запускает функцию JavaScript, которая вызывает вызов Ajax. Сервер возвращает пустую строку, а код JavaScript ничего не делает с ней. Я использую setTimeout для запуска функции каждую секунду, и я использую Drip, чтобы посмотреть эту вещь.

Вот источник:

<html> 
    <head> 
    <script type="text/javascript" src="http://www.google.com/jsapi"></script> 
    <script type="text/javascript"> 
     google.load('jquery', '1.4.2'); 
     google.load('jqueryui', '1.7.2'); 
    </script> 
    <script type="text/javascript"> 
     setTimeout('testJunk()',1000); 
     function testJunk() { 
     $.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string 
       dataType: 'html', 
       success: function(data){} 
       }); 
     setTimeout('testJunk()',1000) 
     } 
    </script> 
    </head> 
    <body> 
    Why is memory usage going up? 
    </body> 
</html> 

Как подключить эту утечку? У меня есть реальное приложение, которое таким образом обновляет большую таблицу, но, оставив без присмотра, она будет потреблять гигабайты памяти.

Edit: хорошо, так что после некоторых хороших предложений, я изменил код:

<html> 
    <head> 
    <script type="text/javascript" src="http://www.google.com/jsapi"></script> 
    <script type="text/javascript"> 
     google.load('jquery', '1.4.2'); 
     google.load('jqueryui', '1.7.2'); 
    </script> 
    <script type="text/javascript"> 
     setTimeout(testJunk,1000); 
     function testJunk() { 
     $.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string 
       dataType: 'html', 
       success: function(data){setTimeout(testJunk,1000)} 
       }); 
     } 
    </script> 
    </head> 
    <body> 
    Why is memory usage going up? 
    </body> 
</html> 

Это не кажется, никакой разницы, хотя. Я ничего не делаю с DOM, и если я прокомментирую вызов Ajax, утечка памяти прекратится. Таким образом, похоже, что утечка полностью связана с вызовом Ajax. Является ли jQuery Ajax по своей сути созданием своего рода циркулярной ссылки, и если да, то как я могу ее освободить? Кстати, это не утечка в Firefox.

Кто-то предложил запустить тест в другой виртуальной машине и посмотреть, будут ли результаты одинаковыми. Вместо того, чтобы настраивать другую виртуальную машину, я обнаружил, что на ноутбуке работает XP Home с Internet Explorer 8. Он обнаружил ту же проблему.

Я попробовал несколько старых версий jQuery и получил лучшие результаты, но проблема не исчезла полностью, пока я не оставил Ajax в jQuery и пошел с более традиционным (и уродливым) Ajax.

+0

Также очень любопытного об ответе - У меня есть идеи, но хочу знать результаты. – Plynx

+0

Хороший вопрос, я не знаю ответа, но вы можете подумать о том, что setTimeout используется в функции успеха, чтобы вы не перегружали сервер, если начинаете делать запросы, требующие времени. Если вы не получили весь ответ с сервера перед отправкой следующего запроса, вы откроете новое соединение. – MyGGaN

+0

Спасибо за предложение о перемещении setTimeout. Я попробовал, но это не помогло. –

ответ

8

Проблема связана с jQuery 1.4 в Internet Explorer и, в меньшей степени, версиями 1.2 и 1.3.

1.4.0, 1.4.1 и 1.4.2 все проявили серьезную утечку памяти.

1.2.3, 1.2.6, 1.3.0, 1.3.1 и 1.3.2 все проявили гораздо меньшую утечку (около 100 КБ через 10 минут).

Я также попробовал версию моей программы, которая вызывает Ajax в более традиционным способом:

<html> 
    <head> 
    <script language="javascript" type="text/javascript"> 
     function getHTTPObject() { 
     var xmlhttp; 
     /*@cc_on 
     @if (@_jscript_version >= 5) 
      try { 
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP"); 
      } catch (e) { 
      try { 
       xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); 
      } catch (E) { 
       xmlhttp = false; 
      } 
      } 
     @else 
     xmlhttp = false; 
     @end @*/ 
     if (!xmlhttp && typeof XMLHttpRequest != 'undefined') { 
      try { 
      xmlhttp = new XMLHttpRequest(); 
      if (xmlhttp.overrideMimeType) { 
       xmlhttp.overrideMimeType("text/xml"); 
      } 
      } catch (e) { 
      xmlhttp = false; 
      } 
     } 
     return xmlhttp; 
     } 
     var ajaxObject = getHTTPObject(); 
     setTimeout(testJunk,1000); 
     function testJunk() { 
     ajaxObject.open('POST', 'http://XXXXXXXXXXXXXXX/delme2', true); 
     ajaxObject.onreadystatechange = handleAjaxResponse; 
     ajaxObject.send(null); 
     } 
     function handleAjaxResponse() { 
     if (ajaxObject.readyState==4) { 
      setTimeout(testJunk,1000); 
     } 
     } 
    </script> 
    </head> 
    <body> 
    <div id="test">Why is memory usage going up?</div> 
    </body> 
</html> 

Это избавились от утечки полностью.

Так что, похоже, мне придется делать повторяющиеся Ajax-вызовы уродливого старого пути, пока люди jQuery не сгладят эту проблему.

+1

Да, если вы хотите продолжать делать вещи в стиле jQuery, используйте патч в моем ответе ... Собственно, вам нужно управлять своим материалом XHR прямо отстой! – Ryley

+0

, как ни странно, мы по-прежнему сталкиваемся с проблемой в текущем JQuery, 1.6.2 во время публикации. Несколько вызовов в .getJSON потребляют все больше и больше памяти, пока вы не убьете процесс, даже если вы ничего не делаете для контента. http://stackoverflow.com/questions/6752335/memory-leak-when-pulling-json-from-web –

5

eval() съест память наверняка (Eval происходит при передаче строки в SetTimeout для оценки), не использовать его в тестировании:

setTimeout('testJunk()',1000); 

должно быть:

setTimeout(testJunk, 1000); 

Также лучше всего использовать setInterval() для повторной операции, как вы хотите, попробуйте следующее:

setInterval(testJunk, 1000); 
+0

Спасибо за предложение. Я попробовал. Если это имело значение, оно было небольшим. Память все еще растет. –

+0

@Thomas - Это целая страница в вашем вопросе, или только сокращенная версия и многое другое происходит в полной версии? –

+0

Я запускаю программу, указанную выше, за исключением того, что я искал URL для листинга. –

0

Одна из проблем с вашим кодом заключается в том, что если ваш запрос ajax начнет занять некоторое время, вы начнете наводнение браузера и сервера с помощью запроса ajax, вам действительно стоит подождать, пока браузер не получит возврат с сервера, прежде чем начинать следующий.

function testJunk() { 
    $.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string 
     dataType: 'html', 
     complete: function(data){ 
      setTimeout(testJunk,1000); 
     } 
    }); 
} 
testJunk(); 
+0

@petersendidit - Лучше всего читать комментарии на вопрос :) –

+0

Спасибо. Я сделал изменения, но я не заметил разницы. –

7

Я столкнулся с той же проблемой и был весь день в тупике ... до нескольких мгновений назад. Проблема заключается в круговой ссылке, которая создается при установке обработчика onreadystatechange, что IE недостаточно умен, чтобы сломаться. Поэтому решение состоит в том, чтобы разбить его явно. Однако, очевидно, вы не можете сделать это из самого обработчика (хотя было бы удобно, если бы вы могли!).

Волшебное заявление:

delete request['onreadystatechange']; 

Вы должны вести учет каждого XMLHttpRequest объекта, для которого вы устанавливаете onreadystatechange. Затем, в какой-то момент после readyState идет до 4, сделайте свою магию на объекте. Если вы уже проводите повторный опрос AJAX, логическое место для проверки запросов на очистку будет в том же цикле опроса. Я определил простой объект RequestTracker для управления моими запросами.

Это сработало для меня; Я проверил, что он решил утечку. Вот одна ссылка, в частности, что привело путь (я вывесил бы больше, но StackOverflow не давая мне):

+1

+1 Отличные исследования, это обязательно будет полезно. – Plynx

19

Вот link жуку над на JQuery, наряду с этим как вариантом решения JQuery 1.4.2:

--- jquery-1.4.2.js  2010-04-08 12:10:20.000000000 -0700 
+++ jquery-1.4.2.js.fixed  2010-04-08 12:10:38.000000000 -0700 
@@ -5219,7 +5219,7 @@ 

          // Stop memory leaks 
          if (s.async) { 
-          xhr = null; 
+          xhr.onreadystatechange = null; xhr.abort = null; xhr = null; 
          } 
        } 
      }; 

ПРИМЕЧАНИЕ: Это официально закреплено в JQuery 1.4.4, так что вам лучше просто обновление.

+2

Это должен быть принятый ответ. +1 –

+0

1.4.4 не исправил это для меня. 1.5 делает хотя –

+0

Я столкнулся с проблемами с использованием этого исправления с jQuery UI 1.8.5, получив ошибку JS «xhr.abort не является функцией». –

0

Я видел это, и я не считаю, что это утечка памяти. Это просто, что запрос Ajax возвращается без данных из-за кэширования.

Добавить преднамеренный контроль кэша, как:

$.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string 
     dataType: 'html', 
     cache: false, 
     success: function(data){} 
    }); 
    setTimeout('testJunk()',1000) 

Это одна из тех вещей, где материал падает вниз трещины, то есть, делает конкретную вещь с кэшированием и XMLHttpRequest и JQuery не использует кэш выключен по умолчанию.

0

Только что это произошло. Я думал, что это как-то связано с библиотекой пользовательского интерфейса, но затем оно исчезло после того, как я поменялся на jQuery 1.5. для версии 1.4.2, которую я использовал. (1.4.4, похоже, не устраняет проблему).

0

Если вы используете setinterval в javascript и не очищаете его должным образом, таймер может запускаться несколько раз, вызывая стек вызовов.

попробовать что-то вроде

var myVar = setInterval(function() { clear() }, 5000); 

function clear() { 
    clearInterval(myVar); 
    GetData("ServiceLibrary","GetCalls",sdata,Complete); 
}; 
Смежные вопросы