У меня есть веб-страница, которая пропускает память как в IE8, так и в Firefox; использование памяти, отображаемое в Проводнике Windows, постоянно растет с течением времени.Утечка памяти с помощью jQuery Ajax-запросов
Следующая страница запрашивает url «unplanned.json», который является статическим файлом, который никогда не меняется (хотя я устанавливаю свой HTTP-заголовок Cache-control
на no-cache
, чтобы убедиться, что запрос Ajax всегда проходит). Когда он получает результаты, он очищает таблицу HTML, перебирает массив json, полученный с сервера, и динамически добавляет строку в таблицу HTML для каждой записи в массиве. Затем он ждет 2 секунды и повторяет этот процесс.
Вот весь веб-страницы:
<html> <head>
<title>Test Page</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
</head> <body>
<script type="text/javascript">
function kickoff() {
$.getJSON("unplanned.json", resetTable);
}
function resetTable(rows) {
$("#content tbody").empty();
for(var i=0; i<rows.length; i++) {
$("<tr>"
+ "<td>" + rows[i].mpe_name + "</td>"
+ "<td>" + rows[i].bin + "</td>"
+ "<td>" + rows[i].request_time + "</td>"
+ "<td>" + rows[i].filtered_delta + "</td>"
+ "<td>" + rows[i].failed_delta + "</td>"
+ "</tr>").appendTo("#content tbody");
}
setTimeout(kickoff, 2000);
}
$(kickoff);
</script>
<table id="content" border="1" style="width:100% ; text-align:center">
<thead><tr>
<th>MPE</th> <th>Bin</th> <th>When</th> <th>Filtered</th> <th>Failed</th>
</tr></thead>
<tbody></tbody>
</table>
</body> </html>
Если это помогает, вот пример JSON я отправляю обратно (именно это точный массив wuith тысяч записей вместо одного):
[
{
mpe_name: "DBOSS-995",
request_time: "09/18/2009 11:51:06",
bin: 4,
filtered_delta: 1,
failed_delta: 1
}
]
EDIT: Я принял чрезвычайно полезный ответ Торан, но я чувствую, что я должен разместить дополнительный код, так как его removefromdom
JQuery плагин имеет некоторые ограничения:
- Он удаляет только отдельные элементы. Поэтому вы не можете дать ему запрос типа `$ (" # content tbody tr ")` и ожидать, что он удалит все указанные вами элементы.
- Любой элемент, который вы удаляете с ним, должен иметь атрибут id. Поэтому, если я хочу удалить свой «tbody», тогда я должен назначить `id` моему тегу tbody, иначе он даст ошибку.
- Он удаляет сам элемент и все его потомки, поэтому, если вы просто хотите опорожнить этот элемент, вам придется его повторно создать (или изменить плагин на пустой, а не удалить).
Так вот моя страница выше, чтобы использовать плагин Toran. Для простоты я не применял ни один из общих рекомендаций по производительности offered by Peter. Здесь нет страницы, которые сейчас не больше утечек памяти:
<html>
<head>
<title>Test Page</title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript">
<!--
$.fn.removefromdom = function(s) {
if (!this) return;
var el = document.getElementById(this.attr("id"));
if (!el) return;
var bin = document.getElementById("IELeakGarbageBin");
//before deleting el, recursively delete all of its children.
while (el.childNodes.length > 0) {
if (!bin) {
bin = document.createElement("DIV");
bin.id = "IELeakGarbageBin";
document.body.appendChild(bin);
}
bin.appendChild(el.childNodes[el.childNodes.length - 1]);
bin.innerHTML = "";
}
el.parentNode.removeChild(el);
if (!bin) {
bin = document.createElement("DIV");
bin.id = "IELeakGarbageBin";
document.body.appendChild(bin);
}
bin.appendChild(el);
bin.innerHTML = "";
};
var resets = 0;
function kickoff() {
$.getJSON("unplanned.json", resetTable);
}
function resetTable(rows) {
$("#content tbody").removefromdom();
$("#content").append('<tbody id="id_field_required"></tbody>');
for(var i=0; i<rows.length; i++) {
$("#content tbody").append("<tr><td>" + rows[i].mpe_name + "</td>"
+ "<td>" + rows[i].bin + "</td>"
+ "<td>" + rows[i].request_time + "</td>"
+ "<td>" + rows[i].filtered_delta + "</td>"
+ "<td>" + rows[i].failed_delta + "</td></tr>");
}
resets++;
$("#message").html("Content set this many times: " + resets);
setTimeout(kickoff, 2000);
}
$(kickoff);
// -->
</script>
<div id="message" style="color:red"></div>
<table id="content" border="1" style="width:100% ; text-align:center">
<thead><tr>
<th>MPE</th>
<th>Bin</th>
<th>When</th>
<th>Filtered</th>
<th>Failed</th>
</tr></thead>
<tbody id="id_field_required"></tbody>
</table>
</body>
</html>
ДАЛЕЕ EDIT: Я оставлю мой вопрос без изменений, хотя стоит отметить, что эта утечка памяти не имеет ничего общего с Ajax. На самом деле, следующий код будет утечка памяти так же и быть столь же легко решается с removefromdom
JQuery плагин Торан в:
function resetTable() {
$("#content tbody").empty();
for(var i=0; i<1000; i++) {
$("#content tbody").append("<tr><td>" + "DBOSS-095" + "</td>"
+ "<td>" + 4 + "</td>"
+ "<td>" + "09/18/2009 11:51:06" + "</td>"
+ "<td>" + 1 + "</td>"
+ "<td>" + 1 + "</td></tr>");
}
setTimeout(resetTable, 2000);
}
$(resetTable);
Невнятный вопрос, но поскольку он добавляет тело к каждой выборке, как он может использовать один и тот же объем памяти? –
Он освобождает тём, прежде чем присоединяться к нему. Я ожидал бы, что опустошенные ряды собирают мусор, хотя кто-то должен определенно сказать мне, ошибаюсь ли я в этом. –
В IE6/7/8 вы не можете по-настоящему удалить динамически созданный элемент DOM, не делая странного рабочего процесса, чтобы обнулить внутреннийHTML (set innerHTML = "") –