¿Qué es la recolección de basura de JavaScript? ¿Qué es importante que un programador web comprenda sobre la recolección de basura de JavaScript para poder escribir un código mejor?
¿Qué es la recolección de basura de JavaScript? ¿Qué es importante que un programador web comprenda sobre la recolección de basura de JavaScript para poder escribir un código mejor?
Respuestas:
Eric Lippert escribió una publicación de blog detallada sobre este tema hace un tiempo (comparándolo adicionalmente con VBScript ). Más exactamente, escribió sobre JScript , que es la propia implementación de ECMAScript de Microsoft, aunque muy similar a JavaScript. Me imagino que puede asumir 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 un navegador a otro, 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 no generacional de marcado y barrido. Funciona así:
Cada variable que está "dentro del alcance" se llama "carroñero". Un carroñero puede referirse a un número, un objeto, una cadena, lo que sea. Mantenemos una lista de carroñeros: las variables se trasladan a la lista de scav cuando entran en el alcance y fuera de la lista de scav cuando salen 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 hay muchos bits adicionales no utilizados en esa estructura, por lo que solo configuramos uno de ellos).
Segundo, borra la marca en los carroñeros y el cierre transitivo de las referencias del carroñero. Entonces, si un objeto carroñero hace referencia a un objeto no carroñero, entonces limpiamos los bits en el no carroñero y en todo lo que se refiere. (Estoy usando la palabra "cierre" en un sentido diferente que en mi publicación anterior).
En este punto, sabemos que toda la memoria aún marcada es memoria asignada a la que ninguna ruta puede acceder desde ninguna variable dentro del alcance. Todos esos objetos tienen instrucciones de destruirse, lo que destruye cualquier referencia circular.
El objetivo principal de la recolección de basura es permitir que el programador no se preocupe por la administración de la memoria de los objetos que crea y usa, aunque, por supuesto, a veces no hay que evitarlo; siempre es beneficioso tener al menos una idea aproximada de cómo funciona la recolección de basura .
Nota histórica: una revisión anterior de la respuesta tenía una referencia incorrecta al delete
operador. En JavaScript, el delete
operador elimina una propiedad de un objeto y es completamente diferente a delete
C / C ++.
delete
incorrectamente; por ejemplo, en el primer ejemplo, en lugar de delete foo
, primero debe eliminar el detector de eventos mediante window.removeEventListener()
y luego usar foo = null
para sobrescribir la variable; en IE, delete window.foo
(pero no delete foo
) también habría funcionado si foo
fuera global, pero incluso así no funcionaría en FF u Opera
delete
es un operador unario (una expresión), no una declaración (es decir:) delete 0, delete 0, delete 3
. Parece una declaración cuando se expresa mediante una declaración de expresión.
Tenga cuidado con las referencias circulares cuando los objetos DOM están involucrados:
Patrones de pérdida de memoria en JavaScript
Tenga en cuenta que la memoria solo se puede recuperar cuando no hay referencias activas al objeto. Este es un error común con los cierres y los controladores de eventos, ya que algunos motores JS no verificarán qué variables se referencian realmente en las funciones internas y solo mantendrán todas las variables locales de las funciones de cierre.
Aquí hay un ejemplo simple:
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 ingenua implementación de JS no se puede recopilar bigString
mientras el controlador de eventos esté disponible. Hay varias formas 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 las propiedades de los objetos, y el objeto variable es inaccesible - ES5 en modo estricto incluso arrojará un ReferenceError
si lo intentas para eliminar una variable local!).
Recomiendo evitar los cierres innecesarios tanto como sea posible si le importa el consumo de memoria.
Buena cita tomada de un blog
El componente DOM es "recolección de basura", al igual que el componente JScript, lo que significa que si crea un objeto dentro de cualquiera de los componentes y luego pierde el rastro de ese objeto, eventualmente se limpiará.
Por ejemplo:
function makeABigObject() {
var bigArray = new Array(20000);
}
Cuando llama a esa función, el componente JScript crea un objeto (llamado bigArray) al que se puede acceder dentro de la función. Sin embargo, tan pronto como la función regrese, "perderá el rastro" de bigArray porque ya no hay forma de referirse a ella. Bueno, el componente JScript se da cuenta de que has perdido el rastro y, por lo tanto, bigArray se limpia y recupera su memoria. El mismo tipo de cosas funciona en el componente DOM. Si dice document.createElement('div')
algo similar, entonces el componente DOM crea un objeto para usted. Una vez que pierda el rastro de ese objeto de alguna manera, el componente DOM limpiará lo relacionado.
Que yo sepa, los objetos de JavaScript son basura recolectada periódicamente cuando no quedan referencias al objeto. Es algo que sucede automáticamente, pero si desea ver más acerca de cómo funciona, a nivel C ++, tiene sentido echar un vistazo al código fuente de WebKit o V8
Por lo general, no necesita pensarlo, sin embargo, en los navegadores más antiguos, como IE 5.5 y versiones anteriores de IE 6, y tal vez las versiones actuales, los cierres crearían referencias circulares que, cuando no se controlan, terminarían consumiendo memoria. En el caso particular al que me refiero sobre cierres, fue cuando agregaste una referencia de JavaScript a un objeto dom, y un objeto a un objeto DOM que se refirió al objeto JavaScript. Básicamente, nunca se pudo recopilar y, con el tiempo, el sistema operativo se volvería inestable en las aplicaciones de prueba que se creaban bloqueos. En la práctica, estas filtraciones suelen ser pequeñas, pero para mantener limpio el código, debe eliminar la referencia de JavaScript al objeto DOM.
Por lo general, es una buena idea usar la palabra clave delete para desreferenciar de inmediato objetos grandes como datos JSON que ha recibido y ha hecho lo que sea necesario, especialmente en el desarrollo web móvil. Esto hace que el próximo barrido del GC elimine ese objeto y libere su memoria.
mark-and-sweep
algoritmos de estilo más nuevos se encargan de esto .
La recolección de basura (GC) es una forma de administración automática de memoria al eliminar los objetos que ya no se necesitan.
cualquier proceso de proceso con memoria sigue estos pasos:
1 - asigna el espacio de memoria que necesitas
2 - haz algo de procesamiento
3 - libera este espacio de memoria
Hay dos algoritmos principales utilizados para detectar qué objetos ya no son necesarios.
Recolección de basura de conteo de referencias : este algoritmo reduce la definición de "un objeto ya no es necesario" a "un objeto no tiene ningún otro objeto que haga referencia a él", el objeto se eliminará si no tiene ningún punto de referencia
Algoritmo de marca y barrido : conecta cada objeto a la fuente raíz. cualquier objeto no se conecta a la raíz u otro objeto. Este objeto será eliminado.
Actualmente, los navegadores más modernos utilizan el segundo algoritmo.
"En informática, la recolección de basura (GC) es una forma de gestión automática de la memoria. El recolector de basura, o simplemente recolector, intenta recuperar la basura o la memoria utilizada por objetos a los que la aplicación nunca volverá a acceder o mutará".
Todos los motores de JavaScript tienen sus propios recolectores de basura, y pueden diferir. La mayoría de las veces no tiene que lidiar con ellos porque simplemente hacen lo que se supone que deben hacer.
Escribir un mejor código depende principalmente de qué tan bueno conoces los principios de programación, el lenguaje y la implementación particular.
¿Qué es la recolección de basura de JavaScript?
mira esto
¿Qué es importante que un programador web comprenda sobre la recolección de basura de JavaScript para poder escribir un código mejor?
En Javascript no te importa la asignación de memoria y la desasignación. Todo el problema se exige al intérprete de Javascript. Las fugas aún son posibles en Javascript, pero son errores del intérprete. Si está interesado en este tema, puede leer más en www.memorymanagement.org
En Windows, puede usar Drip.exe para encontrar pérdidas de memoria o verificar si su rutina de memoria libre funciona.
Es realmente simple, solo ingrese la URL de un sitio web y verá el consumo de memoria del procesador integrado de IE. Luego presione actualizar, si la memoria aumenta, encontró 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.
Los tipos de referencia no almacenan el objeto directamente en la variable a la que está asignado, por lo que la variable de objeto en este ejemplo en realidad no contiene la instancia del objeto. En cambio, contiene un puntero (o referencia) a la ubicación en la memoria donde existe el objeto
var object = new Object();
si asigna una variable a otra, cada variable obtiene una copia del puntero, y ambas aún hacen referencia al mismo objeto en la memoria.
var object1 = new Object();
var object2 = object1;
JavaScript es un lenguaje recolectado de basura , por lo que realmente no necesita preocuparse por las asignaciones de memoria cuando utiliza tipos de referencia. Sin embargo, es mejor desreferenciar objetos que ya no necesita para que el recolector de basura pueda liberar esa memoria. La mejor manera de hacer esto es establecer la variable del objeto en nulo.
var object1 = new Object();
// do something
object1 = null; // dereference
Desreferenciar objetos es especialmente importante en aplicaciones muy grandes que usan millones de objetos.
de Los principios de JavaScript orientado a objetos - NICHOLAS C. ZAKAS