JavaScript: devrais-je me soucier des fuites de mémoire en 2011?

Le sujet des fuites de mémoire en JavaScript n'est pas soulevé souvent. Cependant, je suis tombé sur cet article , écrit en 2007. Les auteurs déclarent:

Internet Explorer et Mozilla Firefox sont les deux navigateurs Web le plus souvent associés à des fuites de mémoire en JavaScript.

Devrais-je encore être préoccupé par les fuites de mémoire JavaScript en 2011? Si oui, à quoi dois-je faire attention?

Un bon développeur javascript serait conscient de divers modèles de conception qui peuvent entraîner des fuites de mémoire et vous éviteriez de coder tout ce qui pourrait transformer en une fuite à peu près toutes les pages que vous codez.

Par exemple, garder une référence à n'importe quel objet DOM dans une variable javascript gardera cet objet DOM en mémoire, même s'il est depuis longtemps supprimé du DOM et que vous souhaitez qu'il soit libéré.

Pratiquement parlant, les fuites ne sont significatives que dans certaines circonstances. Voici où je m'inquiète spécifiquement d'eux:

  1. Tout ce que je fais de façon répétitive sur une minuterie, en particulier s'il peut être laissé en cours d'exécution pendant une longue période. Par exemple, si vous avez un diaporama qui pourrait simplement boucler pour toujours, vous devez absolument s'assurer que rien dans le diaporama n'est une fuite cumulative d'objets JS ou DOM.
  2. Une page Web qui fonctionne comme une application et que l'utilisateur peut rester sur la même page pendant une longue période, interagir avec la page, faire des appels ajax, etc. Par exemple, une application de messagerie Web peut être ouverte et sur le même navigateur réel Document pendant très longtemps en faisant beaucoup et beaucoup d'interactions utilisateur et serveur.
  3. Une page Web qui crée régulièrement et détruit beaucoup d'éléments DOM comme quelque chose qui utilise régulièrement ajax pour récupérer un tas de nouveaux HTML.

Lieux où je ne m'inquiète pas vraiment des fuites:

  1. Une page Web qui ne dispose pas d'un ensemble d'interactions longues que l'utilisateur peut effectuer.
  2. Une page Web qui ne reste plus à l'écran avant qu'une autre page ne soit chargée ou que cette page soit rechargée.

Certaines des choses clés dont je surveille les yeux.

  1. Toutes les variables JS ou propriétés durables qui contiennent des références aux éléments DOM lorsque des éléments DOM sont créés / détruits.
  2. Toutes les propriétés d'un objet DOM qui contiennent des références à d'autres objets DOM ou des références à des objets JS qui contiennent une référence à d'autres objets DOM (cela peut créer des références circulaires et des références croisées entre JS / DOM que certains navigateurs plus anciens ont des problèmes de libération).
  3. Toutes les grandes structures de données que je charge pour une utilisation temporaire. Je m'assure qu'aucune référence à ces grandes structures de données ne soit conservée.
  4. Toute caches de données. Assurez-vous que rien de très grand n'est mis en cache que vous ne voulez pas mettre en cache. Assurez-vous que tous les caches qui s'utilisent à plusieurs reprises ne s'accumulent pas pour toujours et ont une sorte de mécanisme de vieillissement pour éliminer les objets anciens.

Oui, les fuites de mémoire sont certainement un problème en JavaScript, car des références circulaires sont en effet possibles. Une source très courante de fuites de mémoire est l'utilisation de fermetures. À titre d'exemple, considérez:

var outerFunction = function(param1, param2, param3) { var innerFunction = function() {}; return innerFunction; }; 

Il est possible que ci-dessus innerFunction fuite les paramètres, car innerFunction tient une référence à la portée dans laquelle il a été construit, ce qui inclut les paramètres de ce cadre.

Bien qu'il soit facile pour ces types de choses de passer inaperçues sur de nombreux ordinateurs de bureau, où il y a beaucoup de RAM, c'est en fait quelque chose qui peut être très évident sur les périphériques à mémoire vive limitée (p. Ex. Un téléphone mobile ou un décodeur). Comme un exemple anecdotique, un couple de sites Web qui deviendraient anonymes devaient me briser assez fréquemment lorsqu'ils étaient visités par mon téléviseur, qui avait une RAM très limitée.

Notez que ces problèmes sont avec le code JavaScript écrit par les développeurs web. Les fuites de mémoire dans les interprètes JavaScript sous-jacents, si possible, sont beaucoup moins importantes, et ce n'est pas quelque chose dont les développeurs Web peuvent raisonnablement s'inquiéter, car c'est le travail des écrivains du navigateur.

NON.

Réponse plus complète: peut-être. Le fait que vous demandez si vaguement est un signal fort que vous ne devriez pas vous inquiéter personnellement.

Dans la pratique, la grande majorité du code JavaScript ne se soucie pas de cela et n'a pas à s'en préoccuper, car dans des circonstances particulières, les fuites de mémoire dans les pages finissent par affecter les utilisateurs. Le navigateur et les cadres couvrent votre âne très bien.

Il n'y a que quelques questions à répondre:

Q: Êtes-vous en faveur d'une application riche en une seule page qui utilise fortement JavaScript?

Sinon, ne perdez pas votre temps à vous inquiéter. Si vous (ou vos QA, ou vos clients) trouvent un problème de surutilisation de la mémoire avec une page, corrigez-le lorsque cela se produit.

Q: Avez-vous besoin de prendre en charge les appareils mobiles, et vous avez une forte utilisation de javascript?

Les appareils mobiles ont une mémoire limitée et des soins supplémentaires doivent être pris.

Si vous développez une application lourde JavaScript, et vous devez vous soucier de l'utilisation de la mémoire, puis …

La question des références «sales» à des objets qui provoquent des objets JavaScript et des objets DOM pour ne jamais récupérer des déchets est importante pour certains types d'applications JavaScript. Les caches qui se développent à jamais, des références mondiales inattendues et des références inattendues dans des fermetures peuvent constituer un problème.

L'outil Heap Snapshot dans l'inspecteur Web de Chrome peut vous aider.

Voici un projet git qui a une écriture utile et marche les objets javascript qu'il peut: https://github.com/tlrobinson/leakhelper

Il existe d'autres outils qui vous aident, mais j'ai écrit le mien au fil du temps: 1. notre cadre marque des widgets supprimés, j'ai donc écrit un code pour parcourir tous les tableaux et les objets à partir d'une fenêtre ou d'un document recherchant les chemins vers des objets choisis (javascript code peut ' T fermetures à pied, mais il a certainement aidé à trouver des fuites). 2. Un autre truc que j'ai utilisé était lorsque le widget x a été supprimé, je fais un x.leakhelper = window.createElement ('leakhelper') et setAttribute l'oid du widget, mais ne pas ajouter l'élément dans le document. Si l'élément DOM n'est pas collecté, le widget doit y avoir une référence pendante quelque part. Dans IE, utilisez window.collectGarbage () pour forcer le GC, et utilisez sIEve pour détecter l'élément de filtrage de DOM (j'ai trouvé que sIEve était vraiment utile).

Question obsolète: devez-vous soutenir fortement IE6 ou IE7 et utilisez-vous fortement JavaScript? La plupart des fuites effrayantes dont vous avez l'habitude de lire ne se produisent que dans <IE8. Si vous soutenez IE6 ou IE7, vous avez besoin de bonne chance et de persévérance (tous les frameworks fuient, et il est difficile d'écrire un code qui ne fonctionne même pas avec un cadre parfait – j'ai fini par écrire mon propre code de prévention des fuites IE pour notre utilisation de la production Pour les utilisateurs IE6 / 7). Les fuites IE6 / IE7 peuvent durer même après avoir fermé votre page – c'est pourquoi elles sont tellement méchantes.

Eh bien, les personnes utilisent toujours d'anciennes versions d'IE. Alors méfiez-vous des références circulaires, car IE a de graves problèmes avec cela. Je crois que l'erreur commune à cet égard est de faire référence à un élément HTML dans une fermeture qui se trouve dans un gestionnaire d'événements à cet élément. Il suffit de définir la variable se référant à l'élément à null et ce sera bien.

Cela dépend vraiment de 2 choses –

  1. Attentes moyennes d'exécution de votre application. Simple jquery lightbox ou carusel sur la page principale du magasin en ligne peut fuir (et souvent, parce que, ils sont codés si mal), mais personne ne le remarquera (car la page est fermée ou actualisée en quelques minutes ou moins). Mais le serveur Node.js, le réseau social plein-ajax , le jeu de navigateur ou l'IDE en ligne – peuvent fonctionner pendant des heures ou même des jours sans arrêt.

  2. La complexité E / S de votre application. Plus vous touchez DOM, XHR / réseau, fichiers, événements DOM / UI, plus vous redessinez l'écran (qu'il s'agisse de toile, html ou svg) – plus le risque de fuites, le stockage de la mémoire (ce qui n'est PAS une fuite) Et courir sur les bugs du navigateur.

La bonne chose pour vous est – ces deux choses sont en corrélation entre elles. Donc, vous écrivez le code de la piste comme pas demain, ou l'ingénieur pour la performance, l'endurance et la robustesse.

Ps: si vous devez supporter IE8-, vous n'êtes pas encore en 2011. Donc vous devez vous inquiéter, comme dans le bon vieux temps .