У меня есть веб-страница с утечкой памяти в IE8 и Firefox; использование памяти, отображаемое в проводнике Windows, со временем продолжает расти.
На следующей странице запрашивается 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, который я отправляю обратно (именно этот массив содержит тысячи записей вместо одной):
[
{
mpe_name: "DBOSS-995",
request_time: "09/18/2009 11:51:06",
bin: 4,
filtered_delta: 1,
failed_delta: 1
}
]
РЕДАКТИРОВАТЬ: Я принял чрезвычайно полезный ответ Торана, но я чувствую, что должен опубликовать дополнительный код, так как его плагин removefromdom
jQuery имеет некоторые ограничения:
- Удаляет только отдельные элементы. Поэтому вы не можете задать ему запрос типа `$ (" # content tbody tr ")` и ожидать, что он удалит все указанные вами элементы.
- Любой элемент, который вы удаляете вместе с ним, должен иметь атрибут `id`. Поэтому, если я хочу удалить свой `tbody`, я должен присвоить` id` моему тегу `tbody`, иначе он выдаст ошибку.
- Он удаляет сам элемент и всех его потомков, поэтому, если вы просто хотите очистить этот элемент, вам придется заново его создать (или изменить плагин, чтобы он опустел вместо удаления).
Итак, моя страница выше модифицирована для использования плагина Торана. Для простоты я не применил ни одного общего совета по производительности , предложенного Питером . Вот страница, на которой больше нет утечек памяти:
<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>
ДОПОЛНИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ: Я оставлю свой вопрос без изменений, хотя стоит отметить, что эта утечка памяти не имеет ничего общего с Ajax. На самом деле, следующий код будет точно таким же утечкой памяти и будет легко решаться с помощью плагина Toran 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);