Простой jQuery Ajax вызывает утечку памяти в Internet Explorer
Я создал веб-страницу, которая делает вызов Ajax каждую секунду. В Internet Explorer 7 он плохо протекает в памяти (20 МБ за 15 минут).
Программа очень проста. Он просто запускает функцию 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>
Как подключить эту утечку? У меня есть реальное приложение, которое таким образом обновляет большую таблицу, но оставлено без присмотра, оно будет потреблять гигабайты памяти.
Изменить: хорошо, поэтому после некоторых хороших предложений я изменил код на:
<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.
Ответы
Ответ 1
Проблема связана с 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 не сгладят эту проблему.
Ответ 2
Здесь ссылка с ошибкой в 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, поэтому лучше всего обновить его сейчас.
Ответ 3
Я столкнулся с той же проблемой и был весь день в тупике... до нескольких мгновений назад. Проблема заключается в циклической ссылке, которая создается, когда вы устанавливаете обработчик onreadystatechange
, что IE недостаточно умен, чтобы ломаться. Поэтому решение состоит в том, чтобы разбить его явно. Однако, очевидно, вы не можете сделать это из самого обработчика (хотя было бы удобно, если бы вы могли!).
Магическое утверждение:
delete request['onreadystatechange'];
Вам нужно сохранить запись каждого объекта XMLHttpRequest
, для которого вы установили onreadystatechange
. Затем, в какой-то момент после readyState
переходит в 4, сделайте свою магию на объекте. Если вы уже проводите повторный опрос AJAX, логическое место для проверки запросов на очистку будет в том же цикле опроса. Я определил простой объект RequestTracker
для управления моими запросами.
Это сработало для меня; Я проверил, что он решил утечку. Здесь одна ссылка, в частности, которая вела путь (я бы опубликовал больше, но StackOverflow не позволяет мне):
Ответ 4
eval()
наверняка доберется до памяти (eval происходит при передаче строки в значение setTimeout), не используйте ее при тестировании:
setTimeout('testJunk()',1000);
должен быть:
setTimeout(testJunk, 1000);
Лучше всего использовать setInterval()
для повторной операции, как вы хотите, попробуйте следующее:
setInterval(testJunk, 1000);
Ответ 5
Одна проблема с вашим кодом заключается в том, что если ваш запрос ajax начнет занять некоторое время, вы начнете наводнение браузера и сервера с помощью запроса ajax, вам действительно стоит подождать, пока браузер не получит возврат с сервера, прежде чем начать следующий.
function testJunk() {
$.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
dataType: 'html',
complete: function(data){
setTimeout(testJunk,1000);
}
});
}
testJunk();
Ответ 6
Я видел это, и я не считаю, что это утечка памяти. Это просто, что запрос Ajax возвращается без данных из-за кэширования.
Добавьте преднамеренное управление кешем, как в:
$.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
dataType: 'html',
cache: false,
success: function(data){}
});
setTimeout('testJunk()',1000)
Это одна из тех вещей, где материал падает на трещины, то есть делает что-то конкретное с кешированием и XMLHttpRequest, а jQuery по умолчанию не использует кеш.
Ответ 7
Просто это произошло. Я думал, что это как-то связано с библиотекой пользовательского интерфейса, но затем оно исчезло после того, как я поменялся на jQuery 1.5. для версии 1.4.2, которую я использовал. (1.4.4, похоже, не исправить проблему).
Ответ 8
если вы используете setinterval в javascript и не очищаете его должным образом, таймер может запускаться несколько раз, вызывая стек вызовов.
попробуйте что-то вроде
var myVar = setInterval(function() { clear() }, 5000);
function clear() {
clearInterval(myVar);
GetData("ServiceLibrary","GetCalls",sdata,Complete);
};