2011-04-18 7 views
14

Necesito actualizar una gran cantidad de datos dentro de un intervalo determinado con JavaScript. El problema es que, sin importar qué biblioteca JS use (incluso bare-bone js), todos los navegadores parecen asignar memoria en cada solicitud de AJAX y no pueden liberarla después. Aquí está una muestra cortada con tijeras que deben reproducir el error:Los navegadores siguen comiendo memoria con AJAX + setInterval

<!DOCTYPE html> 
    <html lang="en"> 
     <head> 
      <title>Memleak Test</title> 
      <meta charset="utf-8" /> 
      <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js"></script> 
      <script type="text/javascript"> 

       function readData() { 
        $.getJSON('data.php'); 
       } 

       $(document).ready(function() { 
        setInterval(readData, 1000); 
       }); 
      </script> 
     </head> 
     <body> 
      <div id="content"></div> 
     </body> 
    </html> 

Una página de prueba equivalente está disponible en jsbin

Aquí hay más información sobre esto:

  • También traté de poner el ReadData() funciona como un cierre directamente en la llamada setInterval(). Esto no parece hacer ninguna diferencia.
  • Uso jQuery aquí, pero cualquier otra biblioteca produciría los mismos errores.
  • Mi script data.php solo produce un falso objeto JSON con json_encode() en PHP.
  • Sé que un segundo es un período de tiempo corto aquí, en mi secuencia de comandos de producción el plazo es de 30 segundos. Solo quería ver el efecto más rápido (en la aplicación de producción lleva horas pero luego la memoria también está llena).
  • El problema aquí es que la aplicación estará abierta 24/7.

Parece tan simple que creo que estoy haciendo algo realmente malo aquí, sería genial si algunos de los gurús de JS aquí me pueden ayudar.

+1

En su * real * de la prueba se le manipulando el DOM, a través de '.html' o de otra manera? – karim79

+0

karim79, en mi entorno de producción, por supuesto, manipulo el DOM. Cuando traté de rastrear el problema, pude reducirlo a la llamada ajax y para mi sorpresa esta "fuga" también ocurre sin manipulación DOM. Supongo que el navegador no puede liberar la memoria asignada dentro de la llamada setIntervall, pero no sé cómo evitarlo. – daschl

+0

¿Qué pasaría si lo cambiara para que cada N lo solicite, refresca la página del navegador en lugar de hacer la llamada AJAX? – notJim

Respuesta

0

está sondeando servidor después de cada segundo. Definitivamente consumirá toda la memoria. Lo que sí puedes hacer es establecer un intervalo predefinido. Luego, después de sondear si los datos están disponibles, busque eso y mantenga el intervalo igual, pero si después del sondeo todavía no hay datos disponibles, incremente el intervalo para asegurarse de que el siguiente sondeo se demore. De esta forma puedes reducir la carga.

+0

Hola Ahmad, gracias por tu comentario. Dije en mi publicación inicial que esto está establecido en 30 segundos en la producción y que acaba de establecerse en un segundo para que el problema p se manifieste más rápido. Además, no puedo agregar un retraso porque después de 2 horas la posibilidad de nuevos datos es la misma a partir de ahora. ¡Gracias de cualquier manera! – daschl

+0

@moidaschl De acuerdo, además de limpiar la memoria (recolección de basura) debe poner indicadores en cada carga de datos y no debe cargar todo, sino solo desde ese indicador. Espero que entiendas lo que quise decir. –

+0

Hm no, sería genial si pudieras explicar ese indicador un poco más (¿o tienes algunos enlaces disponibles sobre ese tema?) – daschl

0

Eche un vistazo a esta publicación, ¿podría ayudar?

How can I force Javascript garbage collection in IE? IE is acting very slow after AJAX calls & DOM manipulation

(sugiere el uso de métodos específicos de JQuery que aparentemente tratan de evitar pérdidas de memoria, y mediante un comando de 'eliminar' para tratar de liberar espacio).

+0

Gracias por el enlace. En realidad sucede en todos los navegadores, no solo en IE. Al principio, pensé que mi manipulación de datos estaba produciendo este aumento de memoria, pero luego simplemente ejecuté la consulta AJAX (como puede ver en el ejemplo anterior) y no hago nada más y todavía sube. También probé html() y eliminé cosas, pero no ayuda en este caso. ¡Gracias de cualquier manera! – daschl

+0

Nota, usar eliminar es una mala idea, si está leyendo esta respuesta en 2013 o después, no lo use –

0

Aumentará el uso de memoria ya que está cargando más datos en cada solicitud.

Clicky:

How to free memory after an Ajax request

Memory leak involving jQuery Ajax requests

+0

Hola Calum, gracias por los enlaces. El primero simplemente dice que no puedo hacer nada al respecto, que no es una opción aquí: D. El segundo implica manipular el DOM que no hago aquí y la memoria aún aumenta. En mi aplicación de producción, los manipulo DOM, y tal vez este $ .fn.removefromdom ayuda a reducirlo un poco.gracias :) – daschl

0

Según this jQuery forum thread:

... 
success: function(data) { 

    // the line below prevents the leak, apparently 
    document.getElementById("theContainer").innerHTML = ""; 
    $("#theContainer").html(data); 
} 
+0

hm intenté esto, y también cambié el tiempo a 10 segundos, pero se puede ver claramente en el administrador de tareas que en cada solicitud el mem se levanta pero en el intervalo de tiempo la memoria no se elimina. – daschl

+0

No cambio nada. –

0

¿Usted ha intentado la reutilización de las variables dentro de sus llamadas? En vez de crear nuevas variables donde manejar la respuesta, simplemente use las mismas. Diga

window.myvar = response["myvar"]; 

Es realmente una fuga, esto podría ayudar al recolector de basura. Sin embargo, sería bueno ver el código real de lo que estás haciendo.

4

Un posible problema con el mismo publicado es que si las solicitudes XHR tardan más que el período de encuesta (en promedio) habrá una cola cada vez mayor de solicitudes pendientes. Si el servidor web en sí mismo comienza a acumular solicitudes, esto puede convertirse en un círculo vicioso.

Para evitar este posible caso, utilice una codificación de estilo CPS donde la siguiente acción se realiza utilizando las devoluciones de llamada apropiadas. Es decir, no inicie la siguiente solicitud hasta que se solicite (solicitud anterior completada: éxito o falla): este enfoque se puede usar para crear una cola de solicitud manual con un tamaño controlable si se requieren numerosas solicitudes pendientes.

Además, asegúrese de que los objetos no utilizados sean sean elegibles para la reclamación ya que esta es la causa "estándar" de una "pérdida de memoria" en un lenguaje de GC.

Happy coding.


El código en el mensaje no contiene nada que inherentemente perderá memoria. Posiblemente podría ser un problema interno con jQuery, pero esto es solo una especulación. Además, las herramientas como Firebug que monitorean solicitudes XHR/web pueden consumir cantidades significativas de memoria por lo que es algo que debe verificar y asegurarse de que el comportamiento no sea un Heisenberg.


Además, recuerda que el aumento de uso de la memoria no no indica una pérdida de memoria a menos que crezca sin límites. Un ciclo de recolección de basura solo ocurrirá cuando los hosts lo deseen.

+0

Hola pst, gracias por tus comentarios y opiniones sobre esto. Intenté usar setTimeouts "en éxito" en lugar de setIntervals, pero desafortunadamente esto no cambia el problema. Ahora creo que no es realmente una pérdida de memoria, pero podría ser que cuando cargue un montón de HTML, tal vez esté adjuntado o de alguna manera vinculado al DOM y nunca se haya liberado. Entonces (como dije en mi otro comentario anterior), tal vez sea una buena idea cargar algo de JSON en su lugar y renderizarlo. También creo que el problema no saldría en producción SI los usuarios no tendrían la aplicación abierta las 24 horas, los 7 días de la semana. El intervalo de producción es 30 segundos .... – daschl

+0

... que debería ser tiempo suficiente para liberar los antiguos elementos dom. Tristemente sucede con IE también (donde no tenemos firebug en realidad). Me pregunto cómo los "grandes jugadores" como Facebook o Twitter manejan este caso en sus entornos (chat, transmisión en tiempo real, etc.). – daschl

3

Solo un pensamiento, en lugar de setInterval debe usar setTimeout y luego cuando se agota el tiempo de espera.

De esa manera usted no se corre el riesgo de que el setInterval corriendo si se pierde la noción de que por alguna razón:

creo también que el Ajax jQuery tiene una éxito de devolución de llamada que puede usar como el punto que establece en Tiempo de espera. De esa manera, como se ha mencionado en este hilo en otro lugar, no terminas superponiendo solicitudes.

(acaba de comprobar y hay una devolución de llamada de éxito)

+0

hola rtpHarry, gracias por sus comentarios. Como dije en mis comentarios anteriores, probé esto y no cambió la carga de memoria, lamentablemente. ¡Gracias de cualquier manera! – daschl

Cuestiones relacionadas