[Résolu] Gestion de mémoire dealloc-release
kasey
Membre
Bonjour,
Alor voila je vous explique mon problème : j'ai réaliser une petite classe toute bête dans le but de télécharger des fichiers a la volée en appelant simplement ma classe. Seulement il se trouve que je gère mal la mémoire et que soit l'application crash soit j'ai une fuite de mémoire.
je pense qu'il sajit ici d'un cas typique de débutant, mais j'ai beau plonger et replonger dans Cocoa par la pratique, j'ai un peu de mal a assimiler les mecanismes de mémoire.
Pouriez-vous jetter un coup d'oeil a ma classe et m'aider un peu lié tout ça dans ma tête?
Merci d'avance
Et merci a Bru pour son exemple
Alor voila je vous explique mon problème : j'ai réaliser une petite classe toute bête dans le but de télécharger des fichiers a la volée en appelant simplement ma classe. Seulement il se trouve que je gère mal la mémoire et que soit l'application crash soit j'ai une fuite de mémoire.
je pense qu'il sajit ici d'un cas typique de débutant, mais j'ai beau plonger et replonger dans Cocoa par la pratique, j'ai un peu de mal a assimiler les mecanismes de mémoire.
Pouriez-vous jetter un coup d'oeil a ma classe et m'aider un peu lié tout ça dans ma tête?
<br />//<br />// CDLSynchrone.m<br />// TestDownloadSynchro<br />//<br />// Created by Kasey on 30/07/08.<br />// Copyright 2008 __MyCompanyName__. All rights reserved.<br />//<br /><br />#import "CDLSynchrone.h"<br /><br />@implementation CDLSynchrone<br />-(void) setUrl:(NSString *)url {<br /> m_url = [[NSString alloc] initWithString:url];<br />}<br /><br />-(void) setDest:(NSString *)path {<br /> m_path = [[NSString alloc] initWithString:path];<br />}<br /><br />-(void) startDownload {<br /> <br /> // création de l'url qui pointe vers la ressource à télécharger<br /> m_NSurl = [NSURL URLWithString:m_url];<br /> <br /> // téléchargement de la ressource pointée par l'url (le résultat est mis en NSData)<br /> m_data = [m_NSurl resourceDataUsingCache:NO];<br /> <br /> // écriture du NSData dans un fichier sur le disque dur à la racine<br /> [m_data writeToFile:m_path atomically:NO];<br /><br />}<br /><br />-(void) dealloc {<br /> [m_url release];<br /> [m_path release];<br /> [m_NSurl release]; //<--- paf patatras<br /> [m_data release]; //<--- paf patatras<br /> <br /> [super dealloc];<br />}<br />@end<br />
Merci d'avance
Et merci a Bru pour son exemple
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
C'est le cas de m_NSUrl et m_data (pas de init, ni de retain). Ce sont des objets alloués en mémoire de manière temporaire. Ils sont donc automatiquement détruits (enfin plutôt releasés) par le système (à la prochaine boucle d'événement).
Dans la doc Apple, vas faire un tour vers la gestion de la mémoire, chapitre NSAutoReleasePool.
Sinon, il y a aussi une fuite mémoire potentielle dans les 2 méthodes set.... Par exemple, si tu fais plusieurs setUrl, les précédentes NSStrings seront perdues et donc jamais détruites.
http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAccessorMethods.html
Il ne faut pas faire une simple affectation, mais faire le retain du nouveau, puis le release de l'ancien avant d'affecter.
2) Pour les crashes, tout est résumé ici dans la doc Apple
Donc il ne fait faire des release que si c'est toi qui a alloué l'objet avec alloc, new ou copy. Si c'est un autre objet qui a alloué ta variable, c'est à lui de se démerder pour la relâcher, et si c'est des variablse créées avec les constructeurs de commodité, ils sont automatiquement placés dans l'autoreleasepool donc pas de release à envoyer non plus.
Bon grillé par No mais moi j'ai mis les URLs :P
m_NSurl et m_data semblent être des variables d'instance de ta classe (vu leur nommage et le fait que tu les déclares pas localement).
Pourtant, tu les construit avec des constructeurs de commodité, qui renvoient des objets autoreleasés.
Conclusion, dès la prochaine runloop, ils n'existeront probablement plus en mémoire, puisqu'ils auront été automatiquement releasés !
Donc pour moi il faut surtout que m_NSurl et m_data soit en fait juste des variables locales à ta méthode [tt]startDownload:[/tt] (car elles n'ont pas besoin d'être des variables d'instance de ta classe à priori en plus). Du coup le fait qu'elles soient autorelease tombe très bien, ça correspond au cas d'utilisation des variables temporaires / locales... et du coup plus besoin d'appeler release dans ton dealloc sur ces variables (ce que tu ne pourrais de toute façon pas faire puisque dans ce scope là elles ne sont pas connues).
Une question tout de même j'ai déjà croisé des new aussi pour crée de nouvelles instances (enfin si l'on peut dire cela ^^)
un new équivaut-il a un alloc ?
2) constructeur de commodité = alloc + init + autorelease
exemple : [tt][NSString string] = [[[NSString alloc] init] autorelease] = [[NSString new] autorelease][/tt]
exemple 2 : [tt][NSString stringWithString:@toto] = [[[NSString alloc] initWithString:@toto] autorelease][/tt]
par contre j'ai recodé ma classe et adapté mon appli mais j'ai toujours une fuite de mémoire...
je sais pas regardez voir si vous comprenez d'où celle-ci peut bien provenir Oo :
Je ne vois vraiment pas...
Si vous trouvez que j'abuse de votre patience n'hésitez pas a me le dire
Si tu fais newDl = [CDLSynchrone alloc]; ca ne vas pas aller : tu as bien créé l'objet newDl mais tu ne l'as pas initialisé (ce que tu dois faire avec une méthode du genre init ou initWithBidule: ...). Cette étape est primordiale lorsque tu crées un objet en Cocoa (en effet, l'implémentation de init par NSObject ne fais pas rien )
Ensuite, je pense que tu t'es planté lorsque tu écris if(!newDL){[newDL dealloc];}. En effet, il faudrait plutot if(newDL){[newDL dealloc];}
Par contre pour [tt]if(!newDL) {[newDL dealloc];}[/tt] si je l'écris [tt]if(newDL) {[newDL dealloc];}[/tt] (ce qui me semble plus logique a moi aussi) l'application essaye de dealloc au premier passage Oo
1) Ne jamais appeler dealloc directement ! On n'appelle que release (ou autorelease) qui appellera tout seul dealloc si besoin (si le retainCount de l'objet passe à zéro)
2) De toute façon tu viens de déclarer newDL ([tt]CDLSynchrone* newDL[/tt]) donc il n'a de toute façon été alloué nulle part avant, c'est une variable locale ! (par contre c'est pas dit qu'elle soit nil, et c'est pour ça que ça appelle dealloc au premier passage : c'est un pointeur non initialisé donc il peut valoir n'importe quoi et pointer sur n'importe quoi puisque pas encore initialisé justement)
En effet l'idée été de désalloué l'instance si une nouvelle devais être crée mais tout simplement ceci passe mieux peut être :
Hop on release comme ça pu de problème :kicking:
J'espère :-\\
Bon ben merci pour tout j'habite dans le sud du coté de Tarbes je te paye un coup pour te remercier quant tu veux
Et l'invitation est valable pour tous les membres de objective-cocoa ^^ mais pas tous du coup sinon mon portefeuille vas pleurer ^^
@laurris
Oui en effet elle est totalement déprécié et tellement bugged que j'ai recodé ma classe comme ceci :