web-dev-qa-db-fra.com

Puis-je déclencher la récupération de mémoire JavaScript?

Je veux déclencher la récupération de mémoire JavaScript. C'est possible? Pourquoi voudrais-je ou ne veux-je pas faire cela?

39
Abhinav

Je suis parti faire un petit voyage pour chercher une réponse à l'une de vos questions: est-ce possible?

Les gens de toute la ville disent que supprimer les références fera l'affaire. Certaines personnes disent qu'essuyer l'objet est une garantie supplémentaire ( exemple ). J'ai donc écrit un script qui tentera tous les trucs du livre et j'ai été étonné de constater que dans Chrome (22.0.1229.79) et IE (9.0.8112.16421), la récupération de place ne semble même pas fonctionner. Firefox (15.0.1) géré sans aucun inconvénient majeur à part un (voir le cas 4f ci-dessous).

Dans le pseudo-code, le test ressemble à ceci.

  1. Créez un conteneur, un tableau, qui contiendra des objets. Nous appellerons ce conteneur Bertil ici.

  2. En tant qu'élément de Bertil, chaque objet y contenu aura son propre tableau contenant défini comme une propriété. Ce tableau contiendra beaucoup d'octets. Nous appellerons n'importe lequel des éléments de Bertil, l'objet, Joshua. Le tableau d'octets de chaque Josué s'appellera Smith.

    Voici une carte mentale sur laquelle vous pourrez vous appuyer:

    Bertil [Tableau d'objets] -> Joshua [Objet] -> Smith [Tableau d'octets] -> Sans nom [Octets].

  3. Lorsque nous avons gâché notre mémoire disponible, attendez-vous une seconde ou deux, puis exécutez l'un des "algorithmes de destruction" suivants:

    4a. Jetez un opérande de suppression sur le conteneur d'objet principal, Bertil.

    4b. Jeter un opérande de suppression sur chaque objet dans ce conteneur, tuer chaque Josué vivant.

    4c. Jetez un opérande delete sur chaque tableau d'octets, les Smiths.

    4d. Attribuez la valeur NULL à chaque Josué.

    4e. Attribuez UNDEFINED à chaque Josué.

    4f. Supprimez manuellement chaque octet que détient Joshua.

    4g. Faites tout ce qui précède en ordre de marche.

Alors, qu'est-ce-qu'il s'est passé? Dans les cas 4a et 4b, aucun récupérateur de mémoire (GC) du navigateur n’est entré en jeu. Dans le cas de 4c à 4e, Firefox a démarré et affiché une preuve de concept. La mémoire a été récupérée peu de temps après. Avec les valeurs par défaut actuelles codées en dur sur certaines des variables utilisées comme configuration de test, les cas 4f et 4e ont provoqué l'arrêt de Chrome. Par conséquent, je ne peux en tirer aucune conclusion. Vous êtes libre de faire vos propres tests avec vos propres variables, des liens seront bientôt postés. IE a survécu aux cas 4f et 4e mais son GC était mort comme d'habitude. De façon inattendue, Firefox a survécu mais n'a pas passé 4f. Firefox a survécu et a passé 4g.

Dans tous les cas où le GC d'un navigateur a échoué, attendre au moins 10 minutes sans résoudre le problème. Et le rechargement de la page entière a doublé l'encombrement de la mémoire.

Ma conclusion est que j'ai dû faire une horrible erreur dans le code ou la réponse à votre question est: Non, nous ne pouvons pas déclencher le GC. Chaque fois que nous essayons de le faire, nous serons sévèrement punis et nous devrions nous mettre la tête dans le sable. S'il vous plaît, je vous encourage à aller de l'avant, essayez ces cas de test par vous-même. Jetez un coup d'oeil dans le code et commentez les détails. Téléchargez également la page, réécrivez le script et voyez si vous pouvez déclencher le CPG de manière plus appropriée. J'ai échoué et je ne peux pas croire que Chrome et IE ne disposent pas d'un collecteur de mémoire fonctionnel.

http://martinandersson.com/dev/gc_test/?case=1

http://martinandersson.com/dev/gc_test/?case=2

http://martinandersson.com/dev/gc_test/?case=3

http://martinandersson.com/dev/gc_test/?case=4

http://martinandersson.com/dev/gc_test/?case=5

http://martinandersson.com/dev/gc_test/?case=6

http://martinandersson.com/dev/gc_test/?case=7

41
Martin Andersson

Vous pouvez activer manuellement le ramasse-miettes JavaScript dans IE et Opera, mais ce n'est pas recommandé, il est donc préférable de ne pas l'utiliser du tout. Je donne des commandes plus simplement à titre d'information.

Internet Explorer:

window.CollectGarbage()

Opera 7+:

window.opera.collect()
7
masterspambot

La collecte des ordures s'exécute automatiquement. Comment et quand il s'exécute et libère des objets non référencés est entièrement spécifique à la mise en œuvre.

Si vous voulez que quelque chose soit libéré, il vous suffit d'effacer toutes les références de votre code javascript. Le ramasse-miettes va alors le libérer.

Autant que je sache, il n’existe aucun moyen de déclencher manuellement le ramassage des ordures.

Si vous expliquez pourquoi vous pensez même avoir besoin de le faire ou souhaitez le faire et que vous nous montrez le code approprié, nous pourrons peut-être vous expliquer quelles sont vos alternatives.

6
jfriend00
  1. Vérifiez votre code pour les variables globales. Il se peut que des données arrivent via un appel ajax qui est stocké, puis référencé quelque part et vous n'en avez pas tenu compte.
  2. En guise de solution, vous devez regrouper le traitement de données volumineuses dans un appel de fonction anonyme et n’utiliser dans cet appel que des variables locales pour éviter de référencer les données dans une portée globale.
  3. Ou vous pouvez affecter à null toutes les variables globales utilisées.
  4. Consultez également cette question . Regardez le troisième exemple dans la réponse. Votre énorme objet de données peut toujours être référencé par la fermeture d’appel asynchrone.
3
mixel

Cette réponse suggère le code de requête de récupération de place suivant pour les navigateurs basés sur Gecko:

    window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
      .getInterface(Components.interfaces.nsIDOMWindowUtils)
      .garbageCollect();        
2
Daniel Wahlberg

J'étais en train de lire la réponse de Trevor Prime et cela m'a fait rire, mais j'ai alors réalisé qu'il était sur quelque chose.

  1. Le rechargement de la page entraîne un «ramassage des ordures».
  2. location.reload () ou des alternatives pour actualiser la page.
  3. JSON.parse/stringify et localStorage.getItem/setItem pour la persistance des données nécessaires.
  4. iframes en tant que pages de rechargement pour l'expérience utilisateur.

Tout ce que vous avez à faire est d’exécuter votre code dans une iframe et d’actualiser sa page tout en sauvegardant les informations utiles dans localStorage. Vous devrez vous assurer que l'iframe se trouve sur le même domaine que la page principale pour accéder à son DOM.

Vous pouvez le faire sans iframe, mais l'expérience utilisateur en souffrira sans doute car la page sera visiblement réinitialisée.

1
maelwyn

Je suis tombé sur cette question et j'ai décidé de partager avec mes récentes découvertes ... J'ai regardé pour voir comment gérer correctement une carte WeakMap dans Chrome et ça a l'air bien:

1) var wm = new WeakMap()

2) var d = document.createElement('div')

3) wm.set(d, {})

à ce stade, la carte faible contient la cause d'entrée d continue de référencer l'élément

4) d = null

à ce stade, rien ne fait référence à l'élément et à son objet faiblement référencé, et après quelques minutes, l'entrée a disparu et les ordures ont été collectées.

quand a fait la même chose mais que l'élément a été ajouté au DOM, il n'a pas été récupéré, ce qui est correct; il a été supprimé du DOM et attend toujours qu'il soit collecté :)

1
GullerYA

Oui, vous pouvez déclencher un nettoyage de la mémoire en rechargeant la page.

Vous voudrez peut-être envisager d'utiliser un modèle d'usine pour réutiliser des objets, ce qui réduira considérablement le nombre d'objets créés. Surtout si vous créez en permanence des objets identiques.

Si vous avez besoin de lire sur Factory Patterns, procurez-vous ce livre "Pro Javascript Design Patterns" de Ross Harmes et Dustin Diaz et publié par APress.

1
Trevor Prime

S'il est vrai qu'il n'y a aucun moyen de déclencher un CPG, comme le suggèrent les autres réponses, le groupe de normes de navigateur approprié devrait alors ajouter une nouvelle fonction JavaScript à la fenêtre ou au document. Il est utile de permettre à la page Web de déclencher un CPG à un moment de son choix, de sorte que les animations et autres opérations hautement prioritaires (sortie audio?) Ne soient pas interrompues par un GC.

Cela pourrait être un autre cas de syndrome "nous l'avons toujours fait de cette façon; ne berce pas le bateau".

AJOUTÉE:

MDN documente une fonction "Components.utils.schedulePreciseGC" qui permet à une page de planifier ultérieurement un GC avec une fonction de rappel appelée une fois le GC terminé. Cela peut ne pas exister dans les navigateurs autres que Firefox; la documentation n'est pas claire. Cette fonction peut être utilisable avant les animations. il doit être testé.

0
David Spector