Acelerar la Liberación de Memoria de ArrayBuffer en JavaScript
El recolector de basura de JavaScript gestiona la memoria de forma automática, pero procesar ArrayBuffers grandes de manera continua (varios MB por segundo) provoca retrasos. En navegadores como Chrome, el uso de memoria se dispara hasta cientos de MB, especialmente con streaming de video. Firefox lo maneja mejor, pero aún ocurren picos. Esto es crítico para procesos de 32 bits y dispositivos móviles con RAM limitada.
ArrayBuffer está diseñado para datos binarios, pero no tiene métodos para liberarlo manualmente ni redimensionarlo. Propuestas como ArrayBuffer.transfer() no están ampliamente soportadas. El estado desprendido de un buffer (byteLength=0, acceso lanza TypeError) permite que el GC lo reclame rápidamente.
Truco de MessageChannel para Desprender ArrayBuffers
MessageChannel transfiere datos entre contextos. Cerrar port2 desprende port1: los datos van directamente al GC sin esperar al bucle de eventos.
const GarbageBin = (() => {
/** @type {MessageChannel | null} */
let messageChannel = null;
/**
* Acelera la liberación de memoria para ArrayBuffer, TypedArray, DataView.
* @param {any} junk
*/
function dispose(junk) {
if (typeof junk === 'object' && junk) {
const buffer = junk.buffer || junk;
if (buffer.byteLength) {
if (!messageChannel) {
messageChannel = new MessageChannel();
messageChannel.port2.close();
}
messageChannel.port1.postMessage(buffer, [buffer]);
}
}
}
return { dispose };
})();
Uso:
let buffer = new ArrayBuffer(1_000_000);
// Trabajar con el buffer...
GarbageBin.dispose(buffer);
buffer = null;
Compatibilidad: Funciona en Chrome 55+, Firefox 50+. Chrome 56 tiene problemas con datos que persisten. Resultado: reducción de 100 MB en pico de memoria en escenarios reales.
Limitaciones: No para montones asm.js (Firefox 49). Inestable entre versiones.
Truco de Worker para Eliminación Masiva de Memoria
Worker.postMessage desprende ArrayBuffer. Terminar el worker (self.close()) libera instantáneamente toda la memoria del hilo.
Optimización: Acumular ~10 MB antes del cierre para minimizar el sobrecoste de crear/destruir.
const GarbageBin = (() => {
const BIN_CAPACITY = 10_000_000;
/** @type {Worker | null} */
let worker = null;
let workerURL = '';
let bytesInWorker = 0;
function dispose(junk) {
if (typeof junk === 'object' && junk) {
const buffer = junk.buffer || junk;
if (buffer.byteLength) {
if (!worker) {
if (!workerURL) {
workerURL = URL.createObjectURL(new Blob([
`'use strict'; self.onmessage = ({data}) => { if (!data) self.close(); };`
], {type: 'application/javascript'}));
}
worker = new Worker(workerURL, {name: 'GarbageBin'});
}
bytesInWorker += buffer.byteLength;
worker.postMessage(buffer, [buffer]);
if (bytesInWorker > BIN_CAPACITY) {
clear();
}
}
}
}
function clear() {
if (worker) {
worker.postMessage(null);
worker = null;
bytesInWorker = 0;
}
}
return { dispose, clear };
})();
Llama a GarbageBin.clear() al cerrar. Resultado: Chrome -310 MB, Firefox -70 MB en pico de memoria.
Problemas: Fugas de espacio de direcciones virtuales en Firefox 55+.
Comparación de Rendimiento y Recomendaciones
Probado durante 40 minutos: ciclos de CPU dentro del margen de error. MessageChannel más lento que Worker en Firefox (pruebas sintéticas).
| Truco | Efecto en Chrome | Efecto en Firefox | Compatibilidad |
|---------------|------------------|-------------------|--------------------|
| MessageChannel | -100 MB | Estable | Baja |
| Worker | -310 MB | -70 MB | Alta (exc. FF 55+)|
- Usa Worker en producción: más fiable, mayor impacto en Chrome.
- Prueba en navegadores objetivo: los algoritmos de GC evolucionan.
- Evita para montones asm.js/WebAssembly.
- Monitorea con perfmon/explorador de procesos para el conjunto de trabajo.
Worker brilla bajo cargas pesadas (video, streams).
Lecciones Clave
- Ambos trucos desprenden ArrayBuffer vía postMessage, acelerando el GC.
- Worker agrupa 10 MB para reducir sobrecoste.
- Impacto: Hasta 310 MB de reducción en pico en streaming de Chrome.
- Sobrecoste de CPU <1% en escenarios reales.
- Prueba compatibilidad: cambios en GC rompen trucos entre versiones.
— Editorial Team
Aún no hay comentarios.