2010-11-12 33 views
6

Acabo de reunirme con un cliente que tiene grandes problemas de pérdida de memoria en su aplicación web Ajax. Así que decidí crear el siguiente caso de prueba para demostrar el problema:Al agregar elementos DOM con jquery append(), ¿se pierde la memoria?

he utilizado por goteo/Tamiz para perfiles de memoria en el siguiente ejemplo (http://home.orange.nl/jsrosman/)

El caso es simple: tengo el siguiente javascript:

<html> 
    <head>  
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.min.js"> 
</script>  
</head>  
<script type="text/javascript"> 

    var lihtml = "<li class='green'>this is a test text</li>"; 

    function populatelist() { 
     for (var i = 0; i < 10000; i++) { 
      $('#listparent').append(lihtml); 
     }  
    }  

    function clearlist() { 
     $('#listparent').empty(); 
     if (typeof (CollectGarbage) == "function") { 
      alert('gc'); 
      CollectGarbage(); 
     }  
    } 


    /* Alternative clearlist with Remove instead of Empty(), still leaks */ 
    function clearlist() { 
     /* test remove the parent itself instead of empty below */ 
     $('#listparent').remove(); 
     $('body').append("<ul id='listparent'>");   
     //$('#listparent').empty(); 
     if (typeof (CollectGarbage) == "function") { 
      alert('gc'); 
      CollectGarbage(); 
     } 
    } 

    /* Edit!, this is the most effective way to release memory so far */ 
    function clearlist() { 
    $('#listparent').html(""); 
    if (typeof (CollectGarbage) == "function") { 
     alert('gc'); 
     CollectGarbage(); 
    } 
} 
</html> 
</script> 

<body> 
    <button onclick="javascript:populatelist()">Populate list</button> 
    <button onclick="javascript:clearlist()">Clear list</button> 
    <ul id="listparent"> 
     <li>kjjk</li> 
    </ul>  
</body> 

</html> 

Cada clic en Rellenar lista anexa 10000 elementos li (representado como texto). Clearlist llama a jquery empty() que supuestamente debería borrar el subárbol DOM y hacerlo elegible para GC.

Ejecuto este caso en sIEve y cada vez que agrego nuevos elementos aumenta el uso de la memoria, nunca lo he visto recoger basura o memoria libre. Ni siquiera cuando el uso de RAM alcanza 1.5GB y aunque intento llamar a GC explícitamente para IE.

Este es el mismo síntoma que vi en el cliente que usó Jquery Ajax para los datos de la lista en lugar de mi contenido estático obv.

¿Estoy creando el DOM de la manera incorrecta? ¿Alguien puede decirme por qué no es basura recolectada, no puedo ver ninguna otra referencia a los elementos DOM en cuanto a por qué no deberían recogerse basura? Otro comportamiento extraño es que a veces el uso de la memoria de memoria incluso aumenta cuando hago clic en la lista vacía (cuando se llama al método jquery empty()).

Si alguien tiene comentarios, estaría MUY feliz.

ACTUALIZACIÓN, he intentado usar $ ('# listparent'). Html ("") que parece liberar el DOM correctamente, al menos se está liberando en sIEve. Supongo que esa es la mejor solución hasta el momento, aunque no tengo ninguna explicación de por qué eliminar() y vaciar() no parece funcionar. ¿Tal vez solo trabajan para elementos agregados estáticamente?

+0

curiosidad, ¿ha intentado esto en varios navegadores? – Prescott

+0

No sIEve solo funciona en IE, no ha probado FFX, principalmente porque IE es el único navegador utilizado por los usuarios de este sistema. – user408346

+0

En realidad $ ('# listparent').html (""); funciona mucho mejor que empty() y remove() y parece liberar todo el DOM. Estoy sin palabras – user408346

Respuesta

1

sí se podría hacer una gran mejora haciendo smthg al igual que

var lihtml = "<li class='green'>this is a test text</li>", 
    listring = ""; 

function populatelist() { 
     for (var i = 0; i < 10000; i++) { 
      listring += lihtml; 
     }  

     $('#listparent').append(listring); 

    }  
... 

limitar el acceso DOM tan pocos como sea posible.

La diferencia es que usted hace 1 sola anexión en lugar de 10 miles anexos. Siempre debe evitar la manipulación del DOM dentro de los ciclos

Editar: en lugar de vaciar() ¿ha tratado de quitar() el ul y luego volver a crearlo de repente?

+0

Esta es una buena sugerencia y lo intenté, el problema aún persiste, sigue goteando y el vacío() no parece liberar el DOM. En serio comienza a perder la fe en jquery. – user408346

+0

He editado mi respuesta –

+1

Intenté eliminar(), sigue teniendo fugas pero quizás un poco menos que vacío() que parece aumentar la memoria en lugar de liberarla. Lo realmente extraño es que $ ('# listparent'). Html (""); hace el truco y libera todo el DOM y la memoria RAM?!? – user408346

1

Sugiero añadiendo a la cadena HTML y después de añadir a la DOM:

function populatelist() { 
    for (var i = 0; i < 10000; i++) { 
     //$('#listparent').append(lihtml); 
     lihtml += "<li class='green'>this is a test text</li>"; 
    }  
}  
populateList(); 
$('#listparent').append(lihtml); 
+0

Igual que a continuación, buena sugerencia pero la fuga permanece. – user408346

0
$('#listparent').html(""); 

obras donde ni vacía() o eliminar() hice. Desearía saber por qué. Supongo que es una solución.

/* Esta es la forma más eficaz para liberar la memoria hasta el momento */

function clearlist() { 
    $('#listparent').html(""); 
    if (typeof (CollectGarbage) == "function") { 
     alert('gc'); 
     CollectGarbage(); 
    } 
Cuestiones relacionadas