Retour à l'accueil

Gestion de la mémoire ArrayBuffer en JS : Astuces

L'article décompose les techniques pour accélérer la libération de grands ArrayBuffer en JS via l'état détaché avec MessageChannel et Worker. Montre le code, résultats des tests (-310 MB dans Chrome), et compatibilité. Pour applications à haute charge comme les flux vidéo.

Astuces de libération de mémoire ArrayBuffer dans les navigateurs
Advertisement 728x90

Accélérer la libération mémoire des ArrayBuffer en JavaScript

Le ramasse-miettes de JavaScript gère la mémoire automatiquement, mais le traitement continu de gros ArrayBuffer (plusieurs Mo par seconde) provoque des lags. Dans des navigateurs comme Chrome, la consommation mémoire explose à plusieurs centaines de Mo, surtout avec le streaming vidéo. Firefox gère mieux, mais des pics persistent. C'est critique pour les processus 32 bits et les appareils mobiles à RAM limitée.

ArrayBuffer est conçu pour les données binaires mais n'offre ni libération manuelle ni redimensionnement. Les propositions comme ArrayBuffer.transfer() ne sont pas largement supportées. L'état détaché d'un buffer (byteLength=0, accès lève TypeError) permet au GC de le récupérer rapidement.

Astuce MessageChannel pour détacher les ArrayBuffer

MessageChannel transfère des données entre contextes. Fermer port2 détache port1 : les données vont directement au GC sans attendre la boucle d'événements.

Google AdInline article slot
const GarbageBin = (() => {
    /** @type {MessageChannel | null} */
    let messageChannel = null;

    /**
     * Accélère la libération mémoire pour 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 };
})();

Utilisation :

let buffer = new ArrayBuffer(1_000_000);
// Travaillez avec le buffer...
GarbageBin.dispose(buffer);
buffer = null;

Compatibilité : Fonctionne sur Chrome 55+, Firefox 50+. Chrome 56 a des problèmes de données persistantes. Résultat : réduction de 100 Mo au pic en scénarios réels.

Limites : Pas pour les tas asm.js (Firefox 49). Instable selon les versions.

Google AdInline article slot

Astuce Worker pour libération mémoire par lots

Worker.postMessage détache ArrayBuffer. Terminer le worker (self.close()) libère instantanément toute la mémoire du thread.

Optimisation : Accumuler ~10 Mo avant arrêt pour minimiser les coûts de création/destruction.

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 };
})();

Appelez GarbageBin.clear() à l'arrêt. Résultat : Chrome -310 Mo, Firefox -70 Mo au pic.

Google AdInline article slot

Problèmes : Fuites d'espace d'adresses virtuelles sur Firefox 55+.

Comparaison performances et recommandations

Testé sur 40 minutes : cycles CPU dans la marge d'erreur. MessageChannel plus lent que Worker sur Firefox (tests synthétiques).

| Astuce | Effet Chrome | Effet Firefox | Compatibilité |

|---------------|---------------|----------------|-------------------|

| MessageChannel | -100 Mo | Stable | Faible |

| Worker | -310 Mo | -70 Mo | Élevée (sauf FF 55+)|

  • Utilisez Worker en production : plus fiable, impact plus fort sur Chrome.
  • Testez dans les navigateurs cibles : les algorithmes GC évoluent.
  • Évitez pour les tas asm.js/WebAssembly.
  • Surveillez avec perfmon/explorateur de processus pour l'ensemble de travail.

Worker excelle sous charges lourdes (vidéo, flux).

Points clés

  • Les deux astuces détachent ArrayBuffer via postMessage, accélérant le GC.
  • Worker regroupe 10 Mo pour réduire les surcoûts.
  • Impact : Jusqu'à 310 Mo de réduction au pic sur Chrome en streaming.
  • Surcharge CPU <1% en scénarios réels.
  • Testez la compatibilité : les changements GC cassent les astuces selon les versions.

— Editorial Team

Advertisement 728x90

Lire ensuite