Fuite mémoire et NSArray

mickadedel

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

Donc, je remplis mon NSArray (Spins) avec des NSNumbers au dé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ù vient la fuite ?

Pour l'écriture dans le NSArray, j'ai essayé 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 à 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.
 
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];
 
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 detachNewThreadSelector:@selector(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....
 
Heu :heu: ... Un conseil ...

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

Ça permet d'avoir
Bloc de code:
 quelque chose
    dans ce genre là
C'est beaucoup plus lisible, et ça permet de garder l'indentation.
 
mickadedel a dit:
Pour l'écriture dans le NSArray, j'ai essayé avec un objet "tampon" NSNumber *tamponNombre
Bloc de code:
do {
////Ecriture
tamponNombre=[NSNumber numberWithDouble:SxNew];
[Spins replaceObjectAtIndex: position withObject:[NSNumber numberWithDouble:SxNew]];
[tamponNombre release];

}while(condition);

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 :confused:
 
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

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

Merci pour vos réponse en tout cas, et faites attention à vos pool dans les boucles ...
 
Comme quoi le principe du garbage collector n'est pas la panacée que certains espèrent. :D
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. :zen:
 
Si, en fait je me suis tromppé en tapant le code, ce que j'avais essayé c'est :
Bloc de code:
do {
////Ecriture
tamponNombre=[NSNumber numberWithDouble:SxNew];
[Spins replaceObjectAtIndex: position withObject:tamponNombre];
[tamponNombre release];

}while(condition);
Mais ce n'était pas une bonne solution. Il fallait bien créer puis releaser une pool dans la boucle pour que la mémoire soit vidée à chaque pas de ses objets temporaires
 
ntx a dit:
Comme quoi le principe du garbage collector n'est pas la panacée que certains espèrent. :D
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. :zen:

oui c'est un gros probleme avec la poubelle :D y a personne pour la vider :p:D
 
Essaye plutôt :
Bloc de code:
do {
////Ecriture
tamponNombre=[[NSNumber alloc] initWithDouble:SxNew];
[Spins replaceObjectAtIndex: position withObject:tamponNombre];
[tamponNombre release];

}while(condition);
:zen:
 
tatouille a dit:
gdb ca marche bien et malloc debug aussi :zen:
: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.
 
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.