Tengo una página web que pierde memoria tanto en IE8 como en Firefox; el uso de la memoria que se muestra en Windows Process Explorer simplemente sigue creciendo con el tiempo.Perdida de memoria que implica solicitudes de jQuery Ajax
La siguiente página solicita la url "unplanned.json", que es un archivo estático que nunca cambia (aunque configuro mi encabezado HTTP Cache-control
en no-cache
para asegurarme de que la solicitud Ajax siempre se realiza). Cuando obtiene los resultados, borra una tabla HTML, realiza un bucle sobre la matriz json que recuperó del servidor y agrega dinámicamente una fila a una tabla HTML para cada entrada en la matriz. Luego espera 2 segundos y repite este proceso.
Aquí está toda la página web:
<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>
Si ayuda, he aquí un ejemplo de la JSON que estoy enviando de vuelta (que es esta matriz exacta no se enfrentó a miles de entradas en lugar de sólo uno):
[
{
mpe_name: "DBOSS-995",
request_time: "09/18/2009 11:51:06",
bin: 4,
filtered_delta: 1,
failed_delta: 1
}
]
EDIT: he aceptado respuesta extremadamente útiles de Toran, pero siento que debo escribir algo de código adicional, ya que su removefromdom
jQuery plugin tiene algunas limitaciones:
- Solo elimina elementos individuales. Por lo tanto, no puede darle una consulta como `$ (" # content tbody tr ")` y esperar que elimine todos los elementos que ha especificado.
- Cualquier elemento que elimine debe tener un atributo `id`. Entonces, si quiero eliminar mi `tbody`, entonces debo asignar un` id` a mi etiqueta `tbody` o de lo contrario dará un error.
- Elimina el elemento en sí y todos sus descendientes, por lo que si simplemente desea vaciar ese elemento, deberá volver a crearlo posteriormente (o modificar el complemento para vaciarlo en lugar de eliminarlo).
Así que aquí está mi página modificada para usar el plugin de Toran. En aras de la simplicidad, no apliqué ninguna de las recomendaciones de rendimiento general offered by Peter. Aquí está la página que ahora no hay pérdidas de memoria más largos:
<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>
hacer otras modificaciones: Voy a dejar mi pregunta sin cambios, aunque vale la pena señalar que esta pérdida de memoria no tiene nada que ver con el Ajax. De hecho, el siguiente código pérdida de memoria de la misma manera y se acaba de resolverse con la misma facilidad con removefromdom
plugin de jQuery de Toran:
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);
pregunta tonta, pero dado que se agrega al cuerpo en cada búsqueda, ¿cómo puede utilizar la misma cantidad de memoria? –
Vacía el tbody antes de anexarlo. Esperaría que las filas vacías fueran recogidas, aunque alguien definitivamente debería decirme si me equivoco al respecto. –
En IE6/7/8 no se puede eliminar realmente un elemento DOM creado dinámicamente sin hacer una extraña solución para anular el innerHTML (set innerHTML = "") –