Я создал веб-страницу, которая выполняет вызов Ajax каждую секунду. В Internet Explorer 7 это пропускает память плохо (20 МБ приблизительно за 15 минут).
Программа очень проста. Это просто выполняет функцию JavaScript, которая выполняет вызов Ajax. Сервер возвращает пустую строку, и код JavaScript ничего не делает с ним. Я использую setTimeout
для выполнения функции каждую секунду, и я использую Каплю для наблюдения вещи.
Вот источник:
Why is memory usage going up?
Как включить эту утечку? У меня есть реальное приложение, которое обновляет большую таблицу этот путь, но оставленный необслуживаемый он съест выше на гигабайты памяти.
Править: хорошо, поэтому после некоторых хороших предложений, я изменил код к:
Why is memory usage going up?
Это, казалось, не имело значения, все же. Я ничего не делаю с DOM, и если я комментирую вызов Ajax, остановки утечки памяти. Таким образом, похоже, что утечка находится полностью в вызове Ajax. Ajax jQuery по сути создает своего рода циклическую ссылку, и если так, как я могу освободить его? Между прочим, это не протекает в Firefox.
Кто-то предложил запустить тест в другом VM, и посмотрите, является ли результатами то же. Вместо того, чтобы настраивать другой VM, я нашел ноутбук, который выполнял XP Домой с Internet Explorer 8. Это показывает ту же проблему.
Я попробовал некоторые более старые версии jQuery и получил лучшие результаты, но проблема не ушла полностью, пока я не отказался от Ajax в jQuery и пошел с более традиционным (и ужасный) Ajax.
Проблема, похоже, связана с 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 не решат эту проблему.
eval ()
наверняка съест память (eval происходит при передаче строки в setTimeout для оценки), не используйте его при тестировании :
setTimeout('testJunk()',1000);
должно быть:
setTimeout(testJunk, 1000);
Также лучше всего было бы использовать setInterval ()
для повторяющейся операции, как вы хотите, попробуйте следующее:
setInterval(testJunk, 1000);
Одна из проблем с вашим кодом заключается в том, что если ваш запрос ajax начнет занимать некоторое время, вы начнете заполнять браузер и сервер запросом ajax, вам действительно следует подождать, пока браузер получает ответ от сервера перед тем, как начать следующий.
function testJunk() {
$.ajax({ url: 'http://xxxxxxxxxxxxxx/test', // The url returns an empty string
dataType: 'html',
complete: function(data){
setTimeout(testJunk,1000);
}
});
}
testJunk();
Я столкнулся с той же проблемой и все утро был в тупике ... всего несколько минут назад. Проблема заключается в циклической ссылке, которая создается при установке обработчика onreadystatechange
, что IE недостаточно умен, чтобы сломаться. Следовательно, решение состоит в том, чтобы явно нарушить его. Однако, очевидно, вы не можете сделать это из самого обработчика (хотя было бы удобно, если бы вы могли!).
Магический оператор:
delete request['onreadystatechange'];
Вам необходимо вести запись для каждого объекта XMLHttpRequest
, для которого вы установили onreadystatechange
. Затем, в какой-то момент после того, как readyState
перейдет в 4, произведите магию над объектом. Если вы уже выполняете повторный опрос AJAX, логическим местом для проверки запросов на очистку будет тот же цикл опроса. Я определил простой объект RequestTracker
для управления своими запросами.
Это сработало для меня; Я убедился, что утечка устранена. Вот, в частности, одна ссылка, которая проложила путь (я бы опубликовал больше, но StackOverflow мне не позволяет):
Вот ссылка на ошибку в 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, так что лучше всего просто обновить сейчас.