# Fuite mémoire et NSArray



## mickadedel (30 Août 2006)

Bonjour &#224; tous. Je suis "novice" en programmation Objective-C. J'ai &#224; peu pr&#232;s compris le syst&#232;me de fonctionnement de la m&#233;moire, mais j'ai un soucis de fuite que je n'arrive pas &#224; comprendre. Je suis sur un programme de simulation num&#233;rique qui n&#233;cessite une boucle &#233;norme (environ 1 million de pas), et un tableau de donn&#233;es &#233;norme aussi. J'&#233;tais arriv&#233; &#224; la limite du tableau C classique (Environ 30000 doubles). Je me suis donc mis au NSArray, mais apr&#232;s la modification de mon code : fuite m&#233;moire ! En fait, il faut que je remplisse le NSArray avec des objets, donc mes valeurs doubles doivent &#234;tre converties en NSNumbers.

Donc, je remplis mon NSArray (Spins) avec des NSNumbers au d&#233;part, puis dans cette fameuse boucle gigantesque, je ne fait que lire ces NSNumbers, et les remplacer par d'autres. Comment faire autrement ?

Voici les principes du code

do
{
//Spins est mon NSArray. Lectures 
Sx=[[Spins objectAtIndex: position] doubleValue];

//Ecritures
[Spins replaceObjectAtIndex: position withObject:[NSNumber numberWithDouble:SxNew]];

}while (condition);
D'o&#249; vient la fuite ? 

Pour l'&#233;criture dans le NSArray, j'ai essay&#233; avec un objet "tampon" NSNumber *tamponNombre
do {
////Ecriture
tamponNombre=[NSNumber numberWithDouble:SxNew];
[Spins replaceObjectAtIndex: position withObject:[NSNumber numberWithDouble:SxNew]];
[tamponNombre release];

}while(condition);

Toujours la fuite ! :hein: 
HELP ME !

Je tiens &#224; souligner que le calcul se fait dans un thread, et donc qu'un NSAutoreleasePool a &#233;t&#233; mis en place au d&#233;but de la m&#233;thode.


----------



## mpergand (30 Août 2006)

mickadedel a dit:
			
		

> Je tiens à souligner que le calcul se fait dans un thread, et donc qu'un NSAutoreleasePool a été mis en place au début de la méthode.



Tu fais bien de souligner que tu es dans un thread, car je crois bien que le problème vient de là.

Ajoute cette ligne dans l'initialisation de ton thread:
[[NSRunLoop currentRunLoop] run];


----------



## mickadedel (30 Août 2006)

J'ai placé [[NSRunLoop currentRunLoop] run]; dans la méthode lancée dans le thread, mais toujours la fuite...

En fait, j'ai du mal avec la gestion des threads.

Je fais un topo sur l'organisation du projet :

CLASSE Control => Interface Builder (Outlets etc...)
Elle contient des méthodes d'accès aux outlets, et des méthodes d'action du style
getTextInformation {
 return TextInformation;
}
elle contient aussi une variable d'instance appelée threadCalcul avec ses accesseurs :
-(thread_t)getThread
{
  return threadCalcul;
}
-(void)setTread: (thread_t)monThread
{
  treadCalcul=monThread;
}

La méthode "Go" qui lance le calcul :
- (IBAction)go: (id)sender
{
	Simulation *maSimu=[[Simulation alloc] init];
	[maSimu launch:self]; //Passage de l'instance de Control en paramètre pour accéder à ses méthodes.(pour pouvoir utiliser les outlets)
	[maSimu release];
}
Simulation étant une Classe contenant une méthode launch qui va détacher un thread pour lancer une méthode Simule (qui est le calcul long dont j'ai parlé)

voici launch :
- (void)launch: (id)ctrl
{
	if([ctrl getThread])
	{  //TEST SI LE THREAD EST DEJA EN MARCHE

              thread_terminate ([ctrl getThread]);
              [ctrl setThread:0]
	}
	[NSThread detachNewThreadSelectorselector(simule: ) toTarget: self withObject: ctrl];

}
- (void)simule: (id)ctrl
{
   CALCUL
}

Je rappelle : quand j'utilise un tableau classique de doubles, mémoire quasiment stable (peut être pas tout à fait d'ailleur....). Avec NSarray ce n'est pas une fuite, mais une inondation !

Désolé pour la longueur du message....


----------



## PA5CAL (30 Août 2006)

Heu  ... Un conseil ...

Pour &#234;tre plus clair, mets ton code entre des balises [CODE] (c'est le # dans la barre de l'&#233;diteur de message).

&#199;a permet d'avoir
	
	



```
quelque chose
    dans ce genre l&#224;
```
C'est beaucoup plus lisible, et &#231;a permet de garder l'indentation.


----------



## mickadedel (30 Août 2006)

Merci du conseil... Je suis aussi novice sur les forum !...


----------



## macaronique (30 Août 2006)

mickadedel a dit:
			
		

> Pour l'écriture dans le NSArray, j'ai essayé avec un objet "tampon" NSNumber *tamponNombre
> 
> ```
> do {
> ...



Il ne faut pas envoyer un message release à tamponNombre, parce que -numberWithDouble renvoie un objet temporaire (déjà ajouté à l'autoreleasepool.)

Mais en fait tu n'utilises jamais tamponNombre


----------



## tatouille (31 Août 2006)

mickadedel a dit:
			
		

> Merci du conseil... Je suis aussi novice sur les forum !...



bah alors remet ca au clair avec le cheminement complet
tu as gdb aussi qui peut grandement t'aider pour ce genre de probleme auquel tout le monde est confronté novice et non novice


----------



## macaronique (31 Août 2006)

tatouille a dit:
			
		

> tu as gdb aussi qui peut grandement t'aider pour ce genre de probleme


Et OmniObjectMeter pour vérifier s'il y a bien une fuite.


----------



## mickadedel (31 Août 2006)

J'ai trouv&#233; la solution &#224; mon soucis : dans la boucle &#233;norme, les objets temporaires cr&#233;&#233;s par les constructeur genre "numberWithDouble:" balance l'objet dans la pool. Le probl&#232;me vient du fait qu'il faut d&#233;truire la pool pour que la m&#233;moire soit lib&#233;r&#233;e, ce que je faisais.................A la fin de la boucle ! il fallait donc initialiser la pool DANS la boucle, et la releaser &#224; la fin de la boucle mais aussi DEDANS !

Merci pour vos r&#233;ponse en tout cas, et faites attention &#224; vos pool dans les boucles ...


----------



## ntx (31 Août 2006)

Comme quoi le principe du garbage collector n'est pas la panacée que certains espèrent. 
Tu peux peut être utiliser le constructeur "non statique" initWithDouble et allouer/désallouer ton objet à chaque boucle. Ca sera sûrement moins lourd que de travailler avec le pool.


----------



## mickadedel (31 Août 2006)

Si, en fait je me suis trompp&#233; en tapant le code, ce que j'avais essay&#233; c'est :

```
do {
////Ecriture
tamponNombre=[NSNumber numberWithDouble:SxNew];
[Spins replaceObjectAtIndex: position withObject:tamponNombre];
[tamponNombre release];

}while(condition);
```
Mais ce n'&#233;tait pas une bonne solution. Il fallait bien cr&#233;er puis releaser une pool dans la boucle pour que la m&#233;moire soit vid&#233;e &#224; chaque pas de ses objets temporaires


----------



## tatouille (31 Août 2006)

ntx a dit:
			
		

> Comme quoi le principe du garbage collector n'est pas la panacée que certains espèrent.
> Tu peux peut être utiliser le constructeur "non statique" initWithDouble et allouer/désallouer ton objet à chaque boucle. Ca sera sûrement moins lourd que de travailler avec le pool.



oui c'est un gros probleme avec la poubelle  y a personne pour la vider


----------



## ntx (31 Août 2006)

Essaye plutôt :

```
do {
////Ecriture
tamponNombre=[[NSNumber alloc] initWithDouble:SxNew];
[Spins replaceObjectAtIndex: position withObject:tamponNombre];
[tamponNombre release];

}while(condition);
```


----------



## tatouille (31 Août 2006)

macaronique a dit:
			
		

> Et OmniObjectMeter pour vérifier s'il y a bien une fuite.



149.95 $  c'est bonbon pour un simple debugger 

gdb ca marche bien et malloc debug aussi


----------



## macaronique (31 Août 2006)

tatouille a dit:
			
		

> gdb ca marche bien et malloc debug aussi


:rose: Je pensais que c'était gratuit... peut-être je l'ai confondu avec MallocDebug. Il y a longtemps que je n'ai pas progammé Cocoa. 

Je voulais simplement dire qu'il faut vérifier qu'il y a vraiment une fuite avant d'en chercher la cause.


----------



## mickadedel (5 Septembre 2006)

Via le moniteur d'activit&#233; tu vois tout de suite la fuite (en tout cas dans mon cas c'&#233;tait flagrant).


----------



## macaronique (6 Septembre 2006)

mickadedel a dit:


> Via le moniteur d'activité tu vois tout de suite la fuite



Oui, mais fais attention. Ça peut donner l'impression qu'il y a une fuite là où il n'y en a pas. La mémoire peut rester allouée à l'application même si les objets ont été désalloués. Ce n'est pas forcément une fuite, la mémoire peut être disponible pour des nouveaux objets que l'application créera. Il vaut mieux employer ObjectAlloc ou MallocDebug.


----------

