Partage

[AS3] Détruire un objet

Le 17 avril 2009 à 8:08:49

Bonjours !
Voici mon problème :
J'ai crée une instance de ma classe Maclasse et à un moment du code je voudrai supprimer cette instance ou du moins libéré de la mémoire qu'occupe cette instance. Comment faire ?
J'ai trouver la méthode removeChild(_nom_instence) mais j'ai l'impression que cette méthode ne détruit pas l'instance mais la « cache » tout simplement,,,
Publicité
Le 17 avril 2009 à 8:08:49
Le 17 avril 2009 à 9:29:26

Alors, la méthode removeChild (il y a aussi removeChildAt(X) qui supprime l'instance à l'index X) supprime une instance de la liste d'affichage. En revanche, elle ne supprime pas les éventuels écouteurs qui font référence à cette instance. Donc, si tu utilises une méthode removeChild sur un objet possédant des écouteurs, flash va lever des erreurs te disant que ces écouteurs font référence à quelque chose d'inexistant.
Il est donc nécessaire de supprimer les écouteurs sur cet objet via la méthode removeEventListener avant de supprimer cet objet de la liste d'affichage.
De plus, quand tu supprimes un objet de la liste d'affichage, avec un index de 10 par exemple, tous les objets ayant un index supérieur à 10 le verront être réduit de 1 ( le 11 passe 10, etc ...). Si tu utilises une boucle qui parcours l'intégralité des enfants d'un objet, il faut donc faire attention.
Exemple :
J'ai un conteneur avec 20 enfants (de 0 à 19), la boucle parcours ces enfants et en supprime un (le 10 par exemple), les index sont remis à jour et vont de 0 à 18. La boucle elle va continuer jusqu'à 19, et risque donc de faire référence à un objet qui n'est plus à cet index. Dans ce genre de boucles, il faut donc parcours de manière décroissante les enfants d'un objet, afin de ne pas avoir de problèmes si l'un d'eux est supprimé.
Le 17 avril 2009 à 10:57:58

Bonjour,

Un Zéro a posté une question similaire un peu plus bas, à la quelle j'avais donné cette réponse :
http://www.siteduzero.com/forum-83-391 [...] html#r3604568

sinon

Citation : Poupix

De plus, quand tu supprimes un objet de la liste d'affichage, avec un index de 10 par exemple, tous les objets ayant un index supérieur à 10 le verront être réduit de 1 ( le 11 passe 10, etc ...). Si tu utilises une boucle qui parcours l'intégralité des enfants d'un objet, il faut donc faire attention.
Exemple :
J'ai un conteneur avec 20 enfants (de 0 à 19), la boucle parcours ces enfants et en supprime un (le 10 par exemple), les index sont remis à jour et vont de 0 à 18. La boucle elle va continuer jusqu'à 19, et risque donc de faire référence à un objet qui n'est plus à cet index. Dans ce genre de boucles, il faut donc parcours de manière décroissante les enfants d'un objet, afin de ne pas avoir de problèmes si l'un d'eux est supprimé.



Si je puis me permettre, il faut plutôt utiliser une boucle while dans ce cas justement. Mais je ne crois pas que cela faisait parti de la question de quanta62 ^^
MysterTy a sa mysterty-cave
Le 17 avril 2009 à 11:41:42

Dans AS3 et le player 9, il existe un processus appelé le ramasse-miette (garbage collector) qui se lance à un moment t (qui lui dépend de la puissance de la machine hôte).
Ce ramasse-miette permet de détruire les objets qui n'ont plus de références et ainsi de libérer de la mémoire.

Lorsque tu fais un removeChild()ou removeChildAt(), l'objet est seulement retiré de la scène (de la liste d'affichage) mais pas de la mémoire. Pour le rendre éligible au ramasse-miettes, tu dois passer sa référence à null et supprimer tous ses écouteurs.

Une fois cela fait,
removeChild(MON_DISPLAY_OBJECT);
MON_DISPLAY_OBJECT = null;

Cela va rendre ton objet éligible au garbage collector. Par contre tu ne peux pas déterminer précisément quand il passera puisque cela dépend de la puissance de la machine hôte. Toutefois, il existe une méthode gc() qui permet de le déclencher manuellement.

Si tu veux détruire plusieurs objets d'un displayContainer, il faut boucler dessus tout en passant les références à null (en prenant soin qu'il n'y ait plus d'écouteurs).

Attention cependant, il faut bien comprendre la différence entre la liste d'affichage et l'allocation de mémoire vive. Les objets d'affichage peuvent avoir une vie hors affichage.

Edit : les fautes >>
Le 17 avril 2009 à 11:54:33

Citation : mysterty


Si je puis me permettre, il faut plutôt utiliser une boucle while dans ce cas justement.


J'ai un gros problème avec les while, si je veux supprimer des objets qui répondent à une condition spécifique, qu'est ce que ça change d'utiliser un while ? Parceque je vais bien être obligé d'incrémenter une variable pour parcourir la liste d'affichage non ?

Citation : Doc de flash


public static function gc():void

Impose le processus de nettoyage de la mémoire.

Pour la version débogueur de Flash Player et des applications AIR uniquement.




Le 17 avril 2009 à 12:01:57

Parce que ce n'est peut-être pas clair :
La méthode gc() ne peut être appelée que dans le débogueur flash, autrement dit elle est ignorée une fois mise sur un site internet, mais le garbage collector est toujours utilisé et se déclenche automatiquement. En bref, on ne peut pas commander le déclenchement du garbage collector lors de l'application finale, mais il s'exécute automatiquement.
MysterTy a sa mysterty-cave
Le 17 avril 2009 à 12:03:09

Le while, ça marche juste pour supprimer des objets d'affichage qui sont dans un même conteneur (grâce à la ré-attribution automatique des index).
Le 18 avril 2009 à 11:51:26

Merci beaucoup pour toute vos réponse elles m'ont bien aider : )
Le 18 avril 2009 à 14:13:02

Dans certains cas, est-il possible de ne pas passer les références à null pour supprimer un objet ?


Je m'explique:

L'objet est créer au sein d'une fonction:

private function genererPartie(nbr:int):void {
	for (var i:int = 0; i < nbr; i++) {
		var monTexte:Texte = new Texte();
		monNiveau.addChild(monTexte);
	}
}


Après l'exécution de la fonction je ne pourrai plus accéder à l'objet via le "monTexte".
Existe-il une référence encore présente ?

Si ces différents objets sont supprimés de la liste d'affichage, vont-ils être éligible à la suppression ?

Le 18 avril 2009 à 17:39:29

Non, tant qu'il existe des références (écouteurs) et que l'objet n'est pas passé à null il ne pourra pas être éligible au garbage.
Le fait de ne pas pouvoir accéder à ton objet monTexte est normal puisque la variable est écrasée à chaque itération.

Pour contourner ce problème, il faudrait utiliser un écouteur avec l'événement ADDED_TO_STAGE et utiliser la notion de couplage faible (currentTarget).
Le 19 avril 2009 à 10:45:11

Tout mes écouteurs sont créés au sein de l'objet Texte();
Et j'utilise justement un :ADDED_TO_STAGE et REMOVED_TO_STAGE...
Le 19 avril 2009 à 13:11:42

Salut.

Et pourquoi tu n'essaierais pas ? Il suffit, si tu compiles depuis Adobe Flash, d'utiliser la classe System pour vérifier comment tout ça se comporte dans ton cas. Tu crées un certain nombre d'objets, et si la perte mémoire est significative après suppression et utilisation du gc, alors c'est que c'est cool. :)

System.totalMemory
System.gc()


Par exemple un Main.as :

package 
{
	import flash.display.Sprite;
	import flash.system.System;
	
	public class Main extends Sprite
	{
		public function Main()
		{
			// Mémoire initiale
			trace("Mémoire initiale : " + System.totalMemory);
			
			// Ajout des objets
			for (var i:int = 0; i < 1000; i++)
			{
				addChild(new Objet());
			}
			
			// Mémoire après ajout
			trace("Mémoire après ajout : " + System.totalMemory);
			
			// Suppression de tous les objets
			while (numChildren) removeChildAt(0);
			
			// Mémoire après suppression
			trace("Mémoire après suppression : " + System.totalMemory);
			
			// Passage du garbage collector
			System.gc();
			
			// Mémoire après passage du garbage collector
			trace("Mémoire après gc : " + System.totalMemory);
		}
	}
}


Et la classe Objet :

package  
{
	import flash.display.Shape;
	import flash.events.Event;
	
	public class Objet extends Shape
	{
		public function Objet() 
		{
			addEventListener(Event.ADDED_TO_STAGE, _init, false, 0, true);
			addEventListener(Event.REMOVED_FROM_STAGE, _supprimer, false, 0, true);
		}
		
		private function _init(e:Event):void
		{
			removeEventListener(Event.ADDED_TO_STAGE, _init);
		}
		
		private function _supprimer(e:Event):void 
		{
			supprimer();
		}
		
		public function supprimer():void
		{
			// Destruction des écouteurs
			if (hasEventListener(Event.ADDED_TO_STAGE))
			{
				removeEventListener(Event.ADDED_TO_STAGE, _init);
			}
			removeEventListener(Event.REMOVED_FROM_STAGE, _supprimer);
		}
	}
	
}


Après faut en tirer les conclusions. ;)

@+
Le 2 décembre 2009 à 1:27:49

Bonjour,

j'ai le meme problemme. Cela fait 3 jour que je me casse la tete a le resoudre en regardant les forum manuel... de plus je ne suis pas encore habitué au addChild de l'AS3

J'ai une boucle qui me créer environ 1000 enfants a la second (oui ca fait bcp ^^)
Les 10 premier seconde de l'anime c très fluide. Passé c 10 secondes ca commence a ramé et a me dégrade mon animation.

Voici le bout de code :
function onEnterFrame(event:Event):void 
{ 
    SoundMixer.computeSpectrum(bytes, false, 0); 

    var n:Number = 0; 

    // left channel 
    for (var i:int = 0; i < CHANNEL_LENGTH; i++)  
    { 
		trace(numChildren);
		trace("Mémoire initiale : " + System.totalMemory);
        n = (bytes.readFloat() * PLOT_HEIGHT); 
		n = Math.abs(n); // Valeur de en Positif

		var couleur = color(); // Couleur aléatoir
		var posy = Math.random()*400+0; // Position y aléatoire
		var posx = Math.random()*550+0; // Position x aléatoire
		var Rayon = n*10/4;
		
		if (Rayon < 1){Rayon = Math.random()*3+1;}
		//if (Rayon > 300){Rayon = 300;}
		
		var type:String = GradientType.RADIAL; 
		var colors:Array = [couleur, 0x000000]; 
		var alphas:Array = [1, 0]; 
		var ratios:Array = [0, 255]; 
		var spreadMethod:String = SpreadMethod.PAD; 
		var interp:String = InterpolationMethod.LINEAR_RGB; 
		var focalPtRatio:Number = 0; 
			 
		var matrix:Matrix = new Matrix(); 
		matrix.createGradientBox(Rayon*2, Rayon*2, Rayon, posx-Rayon, posy-Rayon); 
		
		var contenaire_cercle:MovieClip = new MovieClip(); 
		addChild(contenaire_cercle);
			
		var cercle:Shape = new Shape();

		cercle.graphics.beginGradientFill(type, colors, alphas, ratios,  matrix,  spreadMethod,  interp,  focalPtRatio); 
		cercle.graphics.drawRect(0, 0, 550, 350);
			
		cercle.blendMode="add"; 
		var myTweenAlpha:Tween = new Tween(cercle, "alpha", Strong.easeOut, 0, 1, 1, true);
		
		if (n > 1){
			contenaire_cercle.addChild(cercle);
		}
		trace("name : "+contenaire_cercle.getChildAt(0).name); 
		//trace(numChildren);
		//while(numChildren>100){contenaire_cercle.removeChild(getChildAt(0));} // Suprimme les enfants au bou de 300 enfants
		if(numChildren>200){
			removeChild(getChildAt(1));
			//removeChild(cercle);
			//cercle=null;
		}
		//contenaire_cercle.removeChild(DisplayObject(cercle)); 
		//removeChild( getChildByName("instance2") );
		
	}
    for (i = CHANNEL_LENGTH; i > 0; i--)  
    { 
        n = (bytes.readFloat() * PLOT_HEIGHT);
		//SpotBass(n);
		//SpotAigu(n)
    } 
	//trace(numChildren);
	//contenaire_cercle.removeChildAt(0);
	//while(numChildren>100){contenaire_cercle.removeChild(cercle);} // Suprimme les enfants au bou de 300 enfants
}


Voici le chti bou de code qui "supprime" mes child
if(numChildren>200){
			removeChild(getChildAt(1));
			//removeChild(cercle);
			//cercle=null;
		}


Merci

Edit:
J'ai combiné c deux choses suivante
removeChild(getChildAt(1));
removeChildAt(cercle.numChildren-1); // Aide au vidage de la mémoire je pense.

cela ram bcp moins et le nombre de Children monte bcp moins vite quand je fait un trace();
Et l'utilisation de la memoire ne monte plus comme avant, mais reste a peut près stable.

[AS3] Détruire un objet

× Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
  • Editeur
  • Markdown