2009-05-14 9 views
279

¿Qué es la recolección de basura JavaScript? ¿Qué es importante para un programador web para comprender acerca de la recolección de basura JavaScript, con el fin de escribir un mejor código?¿Qué es la recolección de basura de JavaScript?

+3

vea también http://stackoverflow.com/questions/774357/garbage-collection –

+1

vea también [¿cómo funciona la recolección de basura javascript?] (Http://stackoverflow.com/q/4324133/1048572) – Bergi

Respuesta

185

Eric Lippert escribió un detailed blog post sobre este tema hace un tiempo (además, comparándolo con VBScript). Más exactamente, escribió sobre JScript, que es la propia implementación de Microsoft de ECMAScript, aunque muy similar a JavaScript. Me imagino que puede suponer que la gran mayoría del comportamiento sería el mismo para el motor de JavaScript de Internet Explorer. Por supuesto, la implementación variará de navegador a navegador, aunque sospecho que podría tomar una serie de principios comunes y aplicarlos a otros navegadores.

citado de esa página:

JScript utiliza un recolector de basura marcar y barrido nongenerational. Se funciona así:

  • Cada variable que es "de alcance" que se llama un "tesoro". Un scavenger puede hacer referencia a un número, un objeto, una cadena , lo que sea. Mantenemos una lista de scavengers - las variables se mueven a la lista de scav cuando vienen en el alcance y fuera de la lista de scav cuando salen fuera del alcance.

  • De vez en cuando se ejecuta el recolector de basura . Primero pone una "marca" en cada objeto, variable, cadena , etc. - toda la memoria rastreada por el GC. (JScript utiliza la estructura de datos Variant internamente y no un montón de bits no utilizados adicionales en esa estructura, por lo que acaba de establecer una de ellos.)

  • En segundo lugar, se borra la marca en los carroñeros y la cierre transitivo de referencias de carroñero. Por lo tanto, si un objeto scavenger hace referencia a un objeto nononscavenger , borramos los bits en el nononscavenger, y en todo lo que hace referencia. (Soy usando la palabra "cierre" en un sentido diferente al que en mi publicación anterior .)

  • En este punto, sabemos que toda la memoria marcado todavía se asigna memoria que no se puede llegar en cualquier camino desde cualquier variable en el estudio. Todos los de esos objetos se instruyen a se rompen, lo que destruye cualquier referencia circular.

El objetivo principal de la recolección de basura es permitir que el programador no que preocuparse por la gestión de memoria de los objetos que crean y uso, aunque por supuesto no hay evitando a veces - que siempre es beneficioso tener al menos una idea aproximada de cómo funciona la recolección de basura.

Hay algunos puntos en particular que debe tener en cuenta. El sitio para desarrolladores de Apple tiene some guidelines al respecto. Dos importantes desde allí:

  • Utilice las instrucciones de eliminación. Siempre que cree un objeto usando una nueva instrucción, emparejelo con una declaración de eliminación. Esto garantiza que toda la memoria asociada con el objeto, incluido su nombre de propiedad, esté disponible para la recolección de elementos no utilizados. La declaración de eliminación se trata más en "Liberación de objetos".
  • Use la palabra clave var. Cualquier variable creada sin la palabra clave var se crea en el ámbito global y nunca es elegible para la recolección de basura, presentando la oportunidad de una pérdida de memoria.

Me imagino que las prácticas deben aplicarse a todos los motores de JavaScript (en diferentes navegadores), sin embargo, porque este es un sitio de Apple, que pueden ser algo específico para Safari. (Tal vez alguien podría aclarar eso?)

Espero que ayude.

+3

+1 gran enlace en el sitio de desarrollador de apple –

+4

El enlace está roto. Esta parece ser la nueva ubicación: http://developer.apple.com/safari/library/documentation/ScriptingAutomation/Conceptual/JSCodingGuide/Advanced/Advanced.html –

+0

@Mark: gracias por señalarlo. La publicación se actualiza. – Noldorin

1

¿Qué es la recolección de basura JavaScript?

cheque this

Lo que es importante para un programador web para entender acerca de la recolección de basura de JavaScript, con el fin de escribir mejor código?

En Javascript no le importa la asignación de memoria ni la desasignación. Todo el problema es exigido al intérprete de Javascript. Las fugas aún son posibles en Javascript, pero son errores del intérprete. Si usted está interesado en este tema que puedes leer más en www.memorymanagement.org

+0

¿Podría usted? ¿elaborar? – tghw

+0

¿Cuál de los diversos sistemas de gestión de memoria en el artículo al que se vincula es el utilizado por JavaScript? _ "Las fugas todavía son posibles en Javascript, pero son errores del intérprete". _ - Eso no significa que los programadores de JS simplemente puedan ignorar todo el problema, por ejemplo, existe un problema de referencia circular DOM muy conocido de JS <-> versiones anteriores de IE que podría trabajar en su código JS. Además, la forma en que funcionan los cierres de JS es una característica de diseño, no un error, pero puedes atar trozos de memoria más grandes que los previstos si utilizas cierres "inapropiadamente" (no estoy diciendo que no los uses). – nnnnnn

+3

Las pérdidas de memoria son una bestia en JavaScript. Si estás escribiendo una simple aplicación de "proyecto de colegio", entonces no te preocupes. Pero cuando comienzas a escribir aplicaciones de alto rendimiento a nivel empresarial, la administración de memoria en JavaScript es imprescindible. – Doug

51

Cuidado con referencias circulares cuando se trata de objetos DOM:

Memory leak patterns in JavaScript

Tenga en cuenta que la memoria sólo puede ser reclamado cuando no hay referencias activas al objeto. Este es un escollo común con los cierres y los controladores de eventos, ya que algunos motores JS no verifican qué variables se referencian realmente en las funciones internas y simplemente conservan todas las variables locales de las funciones adjuntas.

Aquí está un ejemplo sencillo:

function init() { 
    var bigString = new Array(1000).join('xxx'); 
    var foo = document.getElementById('foo'); 
    foo.onclick = function() { 
     // this might create a closure over `bigString`, 
     // even if `bigString` isn't referenced anywhere! 
    }; 
} 

Una aplicación JS ingenua no puede cobrar bigString siempre que el controlador de eventos es de alrededor. Hay varias maneras de resolver este problema, por ejemplo, configurar bigString = null al final de init() (delete no funcionará para variables locales y argumentos de función: delete elimina propiedades de objetos, y el objeto variable es inaccesible - ES5 en modo estricto incluso lanzará a ReferenceError si intenta eliminar una variable local!).

Recomiendo evitar los cierres innecesarios tanto como sea posible si se preocupa por el consumo de memoria.

+19

El error de referencia circular DOM es específico de JScript; ningún otro navegador lo sufre sino IE.De hecho, estoy bastante seguro de que la especificación ECMAScript establece explícitamente que el GC debe ser capaz de manejar dichos ciclos: -/ – olliej

+0

@olliej: No veo ninguna mención del GC en la [especificación ECMAScript] (http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf). –

+0

vea también http://point.davidglasser.net/2013/06/27/surprising-javascript-memory-leak.html – Christoph

13

Buena cita tomada de un blog

El componente DOM se "recolector de basura", como es el componente JScript, lo que significa que si crea un objeto dentro de cualquiera de los componentes, y luego pierde la pista de ese objeto, eventualmente será limpiado.

Por ejemplo:

function makeABigObject() { 
var bigArray = new Array(20000); 
} 

Cuando se llama a esa función, el componente JScript crea un objeto (llamado bigArray) que es accesible dentro de la función. Sin embargo, tan pronto como la función regrese, usted "pierde la pista" de bigArray porque ya no hay forma de referirse a ella. Bueno, el componente de JScript se da cuenta de que lo has perdido de vista, por lo que bigArray se limpia: se recupera su memoria. El mismo tipo de cosas funciona en el componente DOM. Si dices document.createElement('div'), o algo similar, el componente DOM crea un objeto para ti. Una vez que pierde la pista de ese objeto de alguna manera, el componente DOM limpiará los relacionados.

13

Según mi leal saber y entender, los objetos de JavaScript son basura recopilada periódicamente cuando no quedan referencias al objeto. Es algo que sucede automáticamente, pero si desea ver más sobre cómo funciona, en el nivel de C++, tiene sentido echar un vistazo a WebKit o V8 source code

Por lo general, no necesita pensar en ello Sin embargo, en navegadores más antiguos, como IE 5.5 y versiones anteriores de IE 6, y tal vez versiones actuales, los cierres crearían referencias circulares que, si no se verificaran, acabarían consumiendo memoria. En el caso particular que me refiero a los cierres, fue cuando agregaste una referencia de JavaScript a un objeto dom y un objeto a un objeto DOM que hacía referencia al objeto JavaScript. Básicamente, nunca se pudo recopilar y, finalmente, provocaría que el sistema operativo se vuelva inestable en las aplicaciones de prueba que se enlazaron para crear bloqueos. En la práctica, estas filtraciones suelen ser pequeñas, pero para mantener su código limpio, debe eliminar la referencia de JavaScript al objeto DOM.

Por lo general, es una buena idea utilizar la palabra clave delete para desmarcar inmediatamente los objetos grandes como datos JSON que ha recibido y hacer lo que tenga que hacer, especialmente en el desarrollo web móvil. Esto hace que el siguiente barrido del GC elimine ese objeto y libere su memoria.

+0

¿El problema de referencia circular JavaScript -> DOM -> JavaScript se resuelve en las versiones más nuevas de IE? Si es así, ¿desde cuándo? Pensé que era muy profundo desde el punto de vista arquitectónico y es poco probable que alguna vez se arregle. ¿Tienes alguna fuente? – erikkallen

+0

Simplemente de forma anecdótica. No he notado las fugas locas en IE 8 ejecutándose en modo estándar, no en modo roto. Ajustaré mi respuesta. –

+1

@erikkallen: sí, el error de GC se ha corregido en las versiones de IE 8+, ya que los antiguos usaban un algoritmo de recolección de basura muy ingenuo, lo que hacía imposible GC un par de objetos que se referían entre sí. Los nuevos algoritmos de estilo 'mark-and-sweep' [se ocupan de esto] (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management). –

3

"En informática, la recolección de basura (GC) es una forma de gestión de memoria automática. El recolector de basura, o simplemente colector, los intentos de recuperar la basura, o la memoria utilizada por los objetos que nunca se pueda acceder o mutado de nuevo por la aplicación ".

Todos los motores de JavaScript tienen sus propios recolectores de basura, y pueden diferir. La mayoría del tiempo no tienes que lidiar con ellos porque simplemente hacen lo que se supone que deben hacer.

Escribir mejor código depende principalmente de qué tan bien conoces los principios de programación, el lenguaje y la implementación particular.

1

En Windows puede usar Drip.exe para encontrar fugas de memoria o comprobar si su rutina de memoria libre funciona.

Es muy simple, solo ingrese la URL de un sitio web y verá el consumo de memoria del renderizador integrado de IE. A continuación, pulse actualizar, si la memoria aumenta, ha encontrado una pérdida de memoria en algún lugar de la página web. Pero esto también es muy útil para ver si las rutinas para liberar memoria funcionan para IE.

6

recolección de basura (GC) es una forma de administración de memoria automática mediante la eliminación de los objetos que ya no se necesitan.

cualquier acuerdo proceso con la memoria siga estos pasos:

1 - asignar su espacio de memoria que necesita

2 - hacer algo de procesamiento

3 - liberar este espacio de memoria

hay dos algoritmo principal utilizado para detectar qué objetos ya no son necesarios.

de referencia de conteo de recolección de basura: este algoritmo reduce la definición de "un objeto ya no es necesario" a "un objeto no tiene otro objeto que se refiere a ella", el objeto será eliminado si no hay punto de referencia para que

Algoritmo de marca y barrido: conecte cada objeto al origen raíz. cualquier objeto no se conecta a la raíz u otro objeto. este objeto será eliminado.

actualmente navegadores más modernos que utilizan el segundo algoritmo.

+1

Y para agregar una fuente de esto, vea el MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management – Xenos

Cuestiones relacionadas