2011-11-13 11 views
8

He investigado bastante sobre esto, pero sobre todo reuniendo otras preguntas, lo que aún deja dudas. En una aplicación que no actualiza la página del navegador en ningún momento y puede vivir durante bastante tiempo (horas) sin cerrar (suponiendo que refrescar una página o navegar a otra reiniciaría el código js), ¿cuál es la mejor manera de garantizar que los objetos estén liberado y que no hay pérdida de memoria.Objetos de la vida de JavaScript y fugas de memoria

Estos son los escenarios específicos me preocupan:

Todo el código de abajo se encuentra dentro de un patrón módulo de revelador.

mycode = function(){}() 

variables dentro de las funciones, estoy seguro de que éste es recogido por el GC bien

function(){ var h = "ss";} 

las variables dentro del módulo, si g = null cuando ya no es necesario?

var g; 
function(){ g = "dd";} 

Y, por último, la vida de un jqXHR: ¿se limpia después de que vuelve? ¿Debería establecerse en nulo en todos los casos como precaución ya sea que se mantenga dentro de una función o módulo?

Si hace esto, es que x limpiado por el GC después de que vuelve ?:

function(){ 
    var x = $.get(); 
    x.done = ...; 
    x.fail = ...; 
} 

¿Qué tal cuando se hace esto, será también ser limpiado después de x retornos ?:

var x; 
function(){ 
    x = $.get(); 
    x.done = ...; 
    x.fail = ...; 
} 

Por último, ¿hay alguna manera de limpiar todas las variables y reiniciar un módulo sin reiniciar el navegador?

+0

Si está pensando en pérdidas de memoria, no debe pensar en las variables. Piense en los objetos y referencias y las implicaciones de accesibilidad que tiene este último para el primero. – delnan

+0

Sí, es solo que pienso en todo en js como una variable, pero entiendo tu punto. Gracias. –

Respuesta

7

variables dentro de las funciones, estoy seguro de que éste es recogido por el GC bien

Sí.

variables dentro del módulo, ¿debería ser n = g cuando ya no es necesario?

Sure.

Y, por último, la vida de un jqXHR: ¿se limpia después de que vuelve? ¿Debería establecerse en nulo en todos los casos como precaución ya sea que se mantenga dentro de una función o módulo?

Varios navegadores han tenido errores relacionados con XHR que causó la onreadystatechange y cualquier cosa que se cerró sobre permanecer incobrable a menos que el dev tuvo la precaución de reemplazarlo con un valor ficticio (xhr.onreadystatechange = new Function('')) pero creo que jQuery se encarga de esto para usted.

Por último, ¿hay alguna forma de limpiar todas las variables y reiniciar un módulo sin reiniciar el navegador?

El estado global asociado con la página ocupará la memoria del navegador hasta que la página se desactive de la pila del historial del navegador. location.replace puede ayudarlo aquí permitiéndole eliminar la página actual y reemplazarla con una nueva versión de la misma aplicación sin expandir la pila del historial.

Reemplace el documento actual con el que se encuentra en la URL proporcionada. La diferencia con el método assign() es que después de usar replace(), la página actual no se guardará en el historial de la sesión, lo que significa que el usuario no podrá usar el botón Atrás para navegar hacia ella.

Cuando se utiliza la palabra "módulo", que no es un término que tiene un significado bien definido para el navegador o su intérprete de JavaScript así que no hay manera de desalojar a un módulo y sólo un módulo de memoria. Hay varias cosas que usted tiene que preocuparse de que puedan mantener las cosas en la memoria:

  1. Las referencias a objetos JavaScript que se han adjuntado a nodos DOM y todo lo que se cierran sobre - manejadores de eventos son un ejemplo muy común.
  2. Live setInterval y setTimeout devoluciones de llamada y todo lo que cierran más.
  3. Propiedades del objeto global y todo lo que cierran.
  4. Como ha señalado, las propiedades de ciertos objetos de host como las instancias de XHR, las devoluciones de llamadas de los trabajadores de la web, etc. y (lo adivinó) de todo lo que cierran.

Cualquier esquema que va a descargar un módulo y solo un módulo tendría que tratar con todos estos y descubrir cuáles de ellos son parte del módulo y cuáles no. Eso es un montón de diferentes tipos de limpieza.

+0

'delete' solo funciona para propiedades, no para' g' aquí. http://jsfiddle.net/hM5ke/ – pimvdb

+0

@pimvdb, gracias. Editado –

+0

IYO, ¿** Sugerirías ** que una variable jqXHR se establezca como nula cuando ya no se requiera? Acabo de configurar un jqXHR; Obtuve mi respuesta, cargué un nuevo html en el div en el que estaba y todavía puedo acceder a la variable. Aunque aprecio que GC lo hará (eventualmente), ¿sería mejor anularlo? o deja que js gc haga su trabajo? –

1

Javascript es un lenguaje recogido de basura. Se basa en el recolector de basura para limpiar la memoria no utilizada. Entonces, esencialmente, debes confiar en que el GC hará su trabajo.

El GC recogerá (eventualmente, no necesariamente de forma inmediata) objetos que usted no puede alcanzar. Si tiene una referencia a un objeto, es posible que todavía esté en uso, por lo que el GC no lo tocará.

Si no tiene ninguna referencia al objeto, directa o indirectamente, entonces el GC sabe que el objeto no puede ser utilizado, y el objeto puede ser recolectado. Entonces, todo lo que tiene que hacer, realmente, es asegurarse de restablecer cualquier referencia al objeto.

Sin embargo, el GC no ofrece garantías sobre cuando el objeto será recogido. Y no deberías preocuparte por eso.

1

Realmente las únicas filtraciones de las que debe preocuparse son los cierres.

function foo(a){ 
    var b = 10 + a; 
    return function(c){ 
     return b + c; 
    } 
} 

var bar = foo(20); 
var baz = bar(5); 

La GC no tiene manera de eliminar var b - que está fuera de alcance. Este es un gran problema con IE, no tanto con Mozilla y mucho menos con Chrome.

+0

Por supuesto, eso no es una fuga permanente. Una vez que la función de retorno obtenga GC'd, entonces 'b' también obtendrá GC'd. – Raynos

+0

Si no me equivoco, 'b' obtiene GC'd cuando no hay referencias a la función devuelta, ya que es el único lugar donde hay una referencia a b después de que' foo' regrese. –

+0

http://msdn.microsoft.com/en-us/library/bb250448(v=vs.85).aspx – AlienWebguy

0

Es el primer ejemplo con 'g', g debe establecerse en nulo. Mantendrá el puntero a "dd" de lo contrario.

En el segundo ejemplo, la 'x' en el primer caso no necesita establecerse en nulo, ya que esa variable "desaparecerá" cuando la función circundante finalice. En el segundo caso, con 'x' fuera de la función, 'x' retendrá todo lo que se le haya asignado, y no se pasará por GC hasta que 'x' se establezca en nulo o en otra cosa.

+1

'" dd "' es una cadena primitiva y solo ese valor en sí mismo; no es un "puntero" a algo en JavaScript. – pimvdb

+0

@pimvdb, dependiendo de cómo el intérprete agrupa los literales de cadena que ocurren dentro de los cuerpos de función, el navegador puede deshacerse de la memoria utilizada para almacenar '" dd "' después de la función 'function() {g =" dd " ; } 'se recoge. –

1

El GC puede recopilar todas las variables a las que ya no puede acceder. Si declara una variable dentro de una función, una vez que la función se abandona, se puede eliminar la variable . Es es, cuando la computadora se queda sin memoria o en cualquier otro momento.

Esto se vuelve más complicado cuando ejecuta funciones asincrónicas como XHR. El hecho y falla cierres pueden acceder a todas las variables declaradas en las funciones externas. Por lo tanto, siempre que se pueda ejecutar hecho y error, todas las variables deben permanecer en la memoria. Una vez que la solicitud finaliza, las variables pueden ser liberadas.

De todos modos, simplemente debe asegurarse de que cada variable se declare lo más profundo posible.

+0

No hay garantía de que una variable * se * elimine una vez que se abandone la función. Solo * puede * eliminarse de ese punto. – pimvdb

+0

Ok, he corregido esto. El interrogador pidió fugas de memoria y esas aparecen si las variables no se pueden recopilar. – Yogu

+0

@pimvdb, estoy de acuerdo en 'is' vs' can', pero los frames de activación son objetos y ni ellos ni las propiedades cerradas que contienen son coleccionables si hay parte del alcance de cualquier cierre en vivo. Los cambios en la semántica 'eval' en ES5 permiten que los cierres se refieran a un subconjunto de un marco de activación, algunas propiedades y otras no, pero los valores de las variables locales no siempre se pueden recolectar solo porque se ha cerrado el marco de activación en el que aparecen. –

1

Como regla general con cualquier lenguaje recogido de basura (esto se aplica a Java, .NET y JavaScript por ejemplo), lo que quiere hacer es asegurarse de que no haya una referencia persistente a un bloque de memoria que usted quiero que el GC lo limpie por ti. Cuando el GC mira un bloque de memoria y descubre que todavía hay algo en el programa que hace referencia a él, entonces evitará liberarlo.

Con respecto a jqXHR, no tiene sentido que los establezca como nulos al final de una llamada de función AJAX. Todos los parámetros de éxito/error/completo de AJAX se liberarán una vez que la función regrese por el GC a menos que jQuery esté haciendo algo extraño como mantener una referencia a ellos.