Ajax и утечки памяти в IE
Ajax and memory leaks at IE
На днях был один фриланс, надо было разобраться почему в библиотечке для javascript использующей ajax имеются утечки памяти при работе в осле.
Вообще javascript не предоставляет особой работы с памятью и должен все подчищать сам за собой.
Посмотрим простой пример работы с XMLHttpRequest:
var count = 0;
function getHttpRequest() {
httpRequest = false;
if (window.XMLHttpRequest) { // Mozilla, Safari,...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
return httpRequest;
}
function getServerData() {
var _request = getHttpRequest();
_request.onreadystatechange = function() {
if (_request.readyState == 4 && _request.status == 200) {
document.getElementById('content').innerHTML = count + "<br/>" + _request.responseText;
count ++;
}
}
_request.open("GET", "test.txt", true);
_request.send(null);
}
function run() {
getServerData();
setTimeout('run()', 100);
}
function getHttpRequest() {
httpRequest = false;
if (window.XMLHttpRequest) { // Mozilla, Safari,...
httpRequest = new XMLHttpRequest();
} else if (window.ActiveXObject) { // IE
try {
httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
return httpRequest;
}
function getServerData() {
var _request = getHttpRequest();
_request.onreadystatechange = function() {
if (_request.readyState == 4 && _request.status == 200) {
document.getElementById('content').innerHTML = count + "<br/>" + _request.responseText;
count ++;
}
}
_request.open("GET", "test.txt", true);
_request.send(null);
}
function run() {
getServerData();
setTimeout('run()', 100);
}
А где-то там в html-коде вызывается что-то типа onload="run()". Не трудно заметить что 10 раз в секунду этот скрипт будет обращаться к страничке и выводить ее сообщение на экран, кроме этого он будет писать число обращений к этой страничке.
Открываем теперь эту страничку в Internet Explorer и смотрим что будет происходить с памятью.
Для простоты я ее разместил у себя на сервачке: http://www.nik0las.ru/blog/files/2009/ajax/bad.html.
После того как я откупорил в своем осле (кстати ради этого даже загрузил, о ужас, венду!) он начал интенсивно пожирать память. Вот график того, сколько он скушал памяти за пару сотен запросов:
Как показало гугление, это довольно известная шняга в ослине. И встречается не только при работе с аяксом, но и в других случаях. Вот пара ссылочек по теме:
http://blogs.msdn.com/gpde/pages/javascript-memory-leak-detector.aspx
http://www.codeproject.com/KB/scripting/leakpatterns.aspx
В двух словая суть процесса такова. Создается два обьекта, один в javascript, а второй в ActiveX, и имеют кросс ссылки друг на друга, и поэтому гарбадж коллекторы не могут нормально удалить эти обьекты. Решение очень простое - удаляем обьект из javascript принудительно.
Для этого надо добавить всего лишь одну строчку в наш код:
if (_request.readyState == 4 && _request.status == 200) {
document.getElementById('content').innerHTML = count + "<br/>" + _request.responseText;
count ++;
_requset = null;
}
document.getElementById('content').innerHTML = count + "<br/>" + _request.responseText;
count ++;
_requset = null;
}
Вот ссылка на исправленный код:
http://www.nik0las.ru/blog/files/2009/ajax/good.html
И картинка расхода памяти на 1к запросов:
Как легко увидеть ничего не течет.
Добавлено 17.06.2009.
Все это верно для версий IE меньше 7, причем говорят что в последней версии 6-го тоже исправлено.