IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

[DOM] Fuite de mémoire closures IE 6 et IE 7


Sujet :

JavaScript

  1. #1
    Candidat au Club
    Inscrit en
    Juin 2009
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 2
    Points : 2
    Points
    2
    Par défaut [DOM] Fuite de mémoire closures IE 6 et IE 7
    Bonjour,

    J’ai un gros problème en javascript avec les closures. J’explique mon affaire : je réalise un treeview en javascript pour le boulot.

    La particularité de ce treeview tient au fait que les niveaux se chargent progressivement. C'est-à-dire que pour des raisons de performances (les treeviews pouvant comporter plusieurs milliers d’éléments), je ne charge que les nœuds de premier niveau au départ. Lorsque l’utilisateur deploie un nœud alors les niveaux suivants sont affichés, etc… Tout se passe côté client.

    J’ai donc implémenté deux classes javascript, une qui s’appelle treeview, et une qui s’appelle tvNode. Je tenais à ce que toutes les fonctions comme le deploiement des nœuds ou encore le highlight d’un nœud ne soient pas des fonctions globales, mais internes à ces deux classes sous forme de méthodes, de façon à pouvoir réutiliser le code au maximum. Je n’utilise donc pas de innerHTML, et je crée mes nœuds avec le DOM et j’assigne mes gestionnaires d’évènements (comme celui gérant le deploiement/reduction d’un nœud) en utilisant addEventListener ou attachEvent. En effet mon treeview doit marcher sur IE et Firefox.

    Or, je bute sur un problème de taille ; le code suivant marche sous IE, Firefox et Chrome, mais il y a une grosse fuite de mémoire sous IE 6 et 7 (il semblerait que ça ne le fasse pas avec IE 8). J’ai beaucoup surfé sur le net pour y remédier et j’ai essayé beaucoup de solutions proposées. Aucune n’a fait l’affaire.

    Dans le fichier zip joint au message se trouve le code du treeview ainsi que le htm et les images qui vont avec. Pour se rendre compte du bug il faut cliquer quelques fois sur les liens (ce qui décharge un treeview et en charge un autre à la place), pour voir la quantité de mémoire utilisée par IE 6 ou 7 grandir dans le gestionnaire des tâches.


    Dans le fichier tvProgressif.js, il y a deux endroits intéressants :

    /*( 2 ) */ --> c'est là que sont crées les closures. Si on commente ces lignes on n'a plus de fuite mémoire, mais les noeuds des treeviews ne sont plus déployables. Peut être que j'attache ces fonctions aux objets du DOM d'une mauvaise façon, ce qui serait la source de tout mes ennuis

    /*( 1 ) */ --> c'est là que je nettoie le DOM avant le chargement d'une nouvelle arborescence, pour éliminer les références circulaires entre le DOM et les fonctions javascripts et ainsi permettre au garbage collector de IE faire son travail de désallocation
    Ca n'a malheureusement pas l'air de marcher... peut être y a t'il une meilleure façon de procéder?

    Merci beaucoup de m'aider car je galère pas mal et depuis un certain temps sur cette histoire.

    PS : j'utilisais innerHTML au début et le problème de fuite mémoire ne se produisait pas, mais bon je préférerais pouvoir utiliser le nouveau qui est bien mieux niveau réutilisabilité
    Fichiers attachés Fichiers attachés

  2. #2
    Expert confirmé
    Avatar de emmanuel.remy
    Inscrit en
    Novembre 2005
    Messages
    2 855
    Détails du profil
    Informations personnelles :
    Âge : 56

    Informations forums :
    Inscription : Novembre 2005
    Messages : 2 855
    Points : 4 045
    Points
    4 045
    Par défaut
    Salut,

    J'ai parcouru et tester ton code et j'arrive à ses observations qui je l'espère te permettront d'avancer:

    - Déjà il est vrai que le Garbage Collector de IE est bugué, concernant les éléments du DOM sur lesquels on colle un gestionnaire d'événement, à partir du moment où une référence circulaire y réside; IE est incapable de remonter le "chain scope" (je ne sais pas comment le traduire)...
    - Une trace permet de voir que a priori ton code n'effectue pas la libération des événements correctement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    function removeNodeListeners(node)
    {
    	var i, len, sPropName, atts;
    	if (node)
    	{
    		atts = node.attributes;
    
    		if (atts) 
    		{
    			len = atts.length;
    			for (i=0; i<len; i++) 
    			{
    				sPropName = atts[i].name;
    				if (typeof node[sPropName] === 'function')
    				{
    	        console.log("removeNodeListeners " + sPropName);			
    					removeEvent (node, sPropName, node[sPropName]);
    					node[sPropName] = null;
    				}
    			}
    		}
    	}
    }
    Cette trace n'apparait jamais (faite pour FF mais idem pour IE). Cela me semble normal car là où je pense que tu attends une fonction (sur l'attribut onclick par exemple) tu as posé un gestionnaire d'événement. Donc tu ne supprimes jamais tes gestionnaires d'événement. Et là où cela se complique c'est que tu fais:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    TvNode.prototype.nodeToDOM = function(oDivParent) { 
    ...
    	var this4Event = this;
    ...
    	addEvent(oImgNode, "click", function(){this4Event.nodeClick();});
    ...
    }
    Le souci c'est certainement que ton TvNode ne peut être libéré par IE étant donné que le gestionnaire d'événement à garder une référence sur this4Event.

    Enfin je pense qu'en matière de mémoire tu pourrais limiter la mémoire (notamment) ainsi:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    //Création ici de 3 fonctions par tvNode
    addEvent(oImgNode, "click", function(){this4Event.nodeClick();}); 
    ...
    addEvent(oImgNode, "click", function(){this4Event.nodeClick();}); 
    ..
    addEvent(oSpanTextNode, "click", function(){this4Event.nodeClick();});
     
     
    //A remplacer plutôt par: (création d'une seule fonction ce qui vu le 
    //nombre de tvNode n'est pas négligeable:
    var fEvent = function(){this4Event.nodeClick();};
     
    addEvent(oImgNode, "click", fEvent); 
    ...
    addEvent(oImgNode, "click", fEvent); 
    ..
    addEvent(oSpanTextNode, "click", fEvent);
    - Ensuite, je me pose la question de l'intérêt pur et simple de cette fonction. Etant donné que tu disposes d'ID pour quasiment chaque noeud, ne peux tu pas intercepter les événements de façon centralisée sur le Tree pour exécuter ensuite le code dans le contexte du noeud concerné ?
    Enfin je me suis aperçu que tu utilises beaucoup de références de type parent/child/sibling au sein de ton Tree/tvNode (+ affectation de fonctions par copie entre les noeuds). Attention car si le Garbage collector est ok (IE et FF) pour ce type d'objet hors DOM, il n'en reste pas moins que c'est rempli de références circulaires ! A surveiller donc au moins pendant la phase de tests..

    ERE

    ERE

  3. #3
    Expert confirmé
    Avatar de le_chomeur
    Profil pro
    Développeur informatique
    Inscrit en
    Février 2006
    Messages
    3 653
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Février 2006
    Messages : 3 653
    Points : 4 835
    Points
    4 835
    Par défaut
    ou sinon ...
    la méthode pour supprimer les évènements et éviter les fuites mémoire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    function purge(CurrentNode){
     
    		//Récupération de tous les noeuds enfants 
    		while (CurrentNode.childNodes.length>0) {
    			//Si le premier enfant a des enfants appel récursif de la méthode
    			if(CurrentNode.firstChild.childNodes.length>0){
    				this.purge(CurrentNode.firstChild);
    			}
    			//Sinon on parcours ses propriétés pour supprimer les évènements lié aux objet, puis destruction de l'objet
    			else{
     
    				var tempo = CurrentNode.firstChild ;
    				var a = tempo.attributes, i, l, n;
    			    if (a) {
    			        l = a.length;
    			        for (i = 0; i < l; i += 1) {
    			            n = a[i].name;
    			            if (typeof tempo[n] === 'function') {
    			                tempo[n] = null;
    			            }
    			        }
    			    }
    				tempo = null;
    				CurrentNode.removeChild(CurrentNode.firstChild);
     
    			}
    		}
    	}
    détruire les noeud ET nuller les évènements

  4. #4
    Candidat au Club
    Inscrit en
    Juin 2009
    Messages
    2
    Détails du profil
    Informations forums :
    Inscription : Juin 2009
    Messages : 2
    Points : 2
    Points
    2
    Par défaut Merci emmanuel pour ton aide...
    Je suis désolé d'avoir mis autant de temps à répondre, mais en fait j'ai trouvé la solution le lendemain de la date de mon post.

    Comme je suis à la bourre au boulot je n'ai pas pris la peine de retourner sur le forum.

    Je te donnerais le code de la solution sitôt que j'en aurais le temps c'est à dire ce soir ou demain.

    Merci encore en tout cas,


+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. fuite de mémoire ?
    Par salseropom dans le forum C
    Réponses: 2
    Dernier message: 12/01/2006, 16h19
  2. Réponses: 1
    Dernier message: 02/12/2005, 14h18
  3. fuite de mémoire
    Par mamag dans le forum MFC
    Réponses: 17
    Dernier message: 19/08/2005, 10h42
  4. Fuite de mémoire en utilisant le template list
    Par schtroumpf_farceur dans le forum Langage
    Réponses: 9
    Dernier message: 18/07/2005, 20h44
  5. Réponses: 8
    Dernier message: 17/10/2002, 12h52

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo