Gestion de memoire
Paisible.fr
Membre
Soit la classe :
et le code suivant :
Lorsque je construit l'immeuble d'Apple j'ai bien l'enchainement de "init, setName et dealloc".
Par contre quand je construit l'immeuble microsoft je n'ai pas le dealloc.
Pourquoi ?
<br />@implementation immeuble<br />- (id)init<br />{<br /> NSLog(@"construction de l'immeuble");<br /><br /> return self;<br />}<br /><br />- (id)dealloc<br />{<br /> NSLog(@"destruction de l'immeuble");<br /><br /> [super dealloc];<br /> return self;<br />}<br /><br />- (void)setName:(NSString *) aName<br />{<br /> NSLog(@"Affection d'un nom a l'immeuble");<br /> mImmeubleName = aName;<br />}<br />- (NSString *)getName<br />{<br /> return mImmeubleName;<br />}<br /><br />@end<br />
et le code suivant :
<br /> .....<br /> Immeuble *unImmeuble;<br /> <br /> unImmeuble = [[Immeuble alloc] init];<br /> [unImmeuble setName:@"Apple one infinite loop"];<br /> [mImmeubleList addObject:unImmeuble];<br /> <br /> [unImmeuble release];<br /> unImmeuble = nil;<br /> <br /> if (1==1)<br /> {<br /> unImmeuble = [[Immeuble alloc] init];<br /> [unImmeuble setName:@"Microsoft redmond"];<br /> [mImmeubleList addObject:unImmeuble];<br /> <br /> [unImmeuble autorelease];<br /> unImmeuble = nil;<br /> }<br /> .....<br />
Lorsque je construit l'immeuble d'Apple j'ai bien l'enchainement de "init, setName et dealloc".
Par contre quand je construit l'immeuble microsoft je n'ai pas le dealloc.
Pourquoi ?
Connectez-vous ou Inscrivez-vous pour répondre.
Réponses
- (id)init
{
NSLog(@construction de l'immeuble);
return self=[super init];
}
Mais ce n'est pas grave car la doc dit :
An object isn't ready to be used until it has been initialized. The init method defined in the NSObject class does no initialization; it simply returns self.
Normalement c'est -(void) dealloc
% pgm
2008-08-30 18:28:33.076 pgm[1103:10b] construction de l'immeuble
2008-08-30 18:28:33.077 pgm[1103:10b] 0x103260
2008-08-30 18:28:33.078 pgm[1103:10b] Affection d'un nom a l'immeuble
2008-08-30 18:28:33.079 pgm[1103:10b] construction de l'immeuble
2008-08-30 18:28:33.079 pgm[1103:10b] 0x1052a0
2008-08-30 18:28:33.080 pgm[1103:10b] Affection d'un nom a l'immeuble
2008-08-30 18:28:33.081 pgm[1103:10b] destruction de l'immeuble : Apple one infinite loop
2008-08-30 18:28:33.081 pgm[1103:10b] destruction de l'immeuble : Microsoft redmond
%
Mais pour répondre précisément à ta question :
il y a, bien entendu, une différence entre release et autorelease.
-autorelease, c'est comme envoyer release, mais le release sera fait "un peu plus tard".
-"un peu plus tard" ne veut pas dire n'importe quand
-en réalité, "autorelease" inscrit ton objet au bassin d'autorelease (autorelease pool). Quand ce bassin sera supprimé, ton objet recevra le release (et sera donc supprimé si c'est son "dernier" release)
-Si tu ne vois pas d'autoreleasepool dans ton code, c'est que Cocoa en crée automatiquement un pour toi dans la boucle événementielle. Au prochain "passage" dans la boucle d'interface, le bassin sera supprimé et recréé
-tu peux très bien créer toi même tes bassins d'autorelease; [[NSAutoreleasePool alloc] init]. Il n'y a rien de particulier à faire pour choisir le bassin dans lequel ton objet sera inscrit : il est automatiquement mis dans le dernier bassin créé.
Essaye cela :
Un truc m'étonne : si tu mes tes immeubles dans mImmeubleList, ce dernier devrait leur faire un "retain", et donc tes objets resteraient forcément en vie tant que mImmeubleList existe.
+
Chacha
Hein ? c'est pas aléatoire du tout... c'est à un moment bien précis :P
- Soit au "release" d'un NSAutoreleasePool perso
- Soit à la fin (début ?) du cycle de runloop
Il y a bien d'autre cas que ceux-là . Si une variable est en autorelease dans une méthode qui ne contient pas de NSAutoreleasePool par exemple, elle est libérée bien avant la fin du run loop, et heureusement ! et là c'est une question de priorité qui n'est pas aléatoire au sens pur du terme certes, mais qui n'est pas gérée par le programme.
Elle ne sera pas libérée avant la fin du cycle de runloop
Et c'est parfaitement contrôlé par le programme :P
Heureusement que c'est pas aléatoire sinon on aurait de sacrés problèmes
La fin du cycle de runloop est un moment stratégique... on a fini tout ce qu'on avait à faire pour le cycle en cours, donc on n'a plus besoin des variables autoreleased ; on entame un nouveau cycle tout neuf
Ce n'est pas l'impression que j'ai eu lors de l'observation du phénomène.
Si une méthode A reçoit d'une autre méthode B une variable qui est en autorelease dans B, elle continue à l'utiliser. Pour cela elle fait une sorte de retain-autorelease sur cette variable, (son retaincount est en général de valeur=2), etc ...
Et à la fin de la seconde méthode peut-être qu'une troisième méthode C sera enclanchée,n'utilisant pas cette variable. Qu'est-ce qui décide alors du déclenchement des release, rien ne presse, et en (bon?) programmeur j'aurais tendance à faire l'urgent plutôt que le secondaire.
Sa durée de vie est donc quelque part indéterminée, on sait simplement qu'elle vit le temps de son utilisation dans le programme.
Quand disparaà®t-elle, on n'en sait rien. Dès que faire se peut sans doute, je pense qu'un thread du programme se charge du nettoyage des autoreleasePool.
Rien ne permet de dire qu'à un instant donné la zone mémoire qu'occupait une variable en autorelease est libérée. Ce n'est pas un free(). Du moins, je n'ai jamais lu un tel engagement de la part d'Objective-C.
On peut considérer qu'il y a une durée de vie minimale assurée, et qu'après c'est aléatoire.
Bref, la retraite à 65 ans, après vous verrez ...
Maintenant, je veux bien voir une doc quelque part disant quelque chose de plus précis que ce que j'avance.
http://developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/Concepts/AutoreleasePools.html#//apple_ref/doc/uid/20000047-CJBFBEDI
Donc en fait plus précisément par rapport à ce que j'ai dit au dessus, au niveau de la run-loop, quand un événement doit être traité, un NSAutoreleasePool est créé, puis détruit à la fin de l'événement (ce qui revient au même que dire qu'il est " drainé " à la fin de la boucle d'événements).
Sur une simple application j'ai deux ou trois NSAutoreleasePool qui ont été créés, dès le début, c'est tout.
Ce que je lis dans la citation : c'est "on s'en occupe", mais cela ne dit pas comment. Pour moi l'Event-Cycle dure toute la durée de vie, pour une application simple tout du moins.
" Dans le cadre des applications Cocoa, le pool de libération automatique est créé avant la gestion de l'événement concerné et il est libéré après. Par conséquent, à moins que les objets du pool de libération automatique ne soient conservés, ils seront détruits dès que l'événement aura été géré. "
Jamais d'aléatoire dans la gestion des NSAutoreleasePool, sauf peut-être dans le cadre de l'utilisation du Garbage Collector avec Obj-C 2.0Â ???
Dans la troisième édition de Hillegass, il dit : "Objects are added to the autorelease pool when they are sent the message autorelease. When the pool is drained, it sends the message release to all objects in the pool. In other words, when an object is autoreleased, it is marked to be sent release sometime in the future"
Après il rajoute la phrase que tu as signalée, qui semble s'appliquer aux events, mais je ne vois pas trop comment cela s'articule avec le programme que l'on fait.
Jamais d'aléatoire lorsque l'on fait [pool drain] ou [pool release], mais quand le pool principal de l'application se libère au fur et à mesure, on sait à partir de quand il peut le faire, mais on ne sait pas quand il le fait. Cela n'est pas en contradiction avec les citations que tu donnes.
En mode debug, on peut donc croire à l'instant t+10 qu'un objet existe encore, alors qu'il est dans le pool à l'instant t, mais non encore détruit.
Je pense que l'aléatoire dont tu parles provient du garbage collector.
Mettre un breakpoint sur la méthode drain de NSAutoreleasePool est également une expérience intéressante, éprouvante pour les nerfs, mais intéressante.
Mais même avec "drain" sans GC, ça m'étonnerait fortement que ça draine aléatoirement.
Il y a forcément un mécanisme logique (sinon c'est plus un langage structuré, c'est du grand n'importe quoi !)
On est d'accord.
Quand je parle d'aléatoire, je pense au modèle de deux threads lancés en concurrence. Les deux fonctionnent, mais le résultat est rarement le même. C'est structuré, mais le résultat n'est pas déterminé à l'avance.
On peut aussi penser à un modèle plus déterministe, comme celui d'un mécanisme de vidage de tampon classique :
• A des moments précis, drain est effectué sur l'autoreleasePool (sans doute sur une boucle d'événements).
• A partir d'un certain degré de remplissage, un drain est effectué sur l'autoreleasePool.
Celui du thread avec une faible priorité est peut-être plus souple à l'utilisation ...
De toutes façons, dans le pool les données sont considérées comme de la mémoire à libérer, et il ne peut y avoir interférence entre un thread gérant la libération du pool commun et un autre thread du programme possédant son propre pool, géré lui-même par un système analogue, sauf erreur de programmation.
J'ai l'impression que tu as en tête un modèle comme quoi à chaque bloc d'instructions un pool est créé, avec drain à la fin du bloc. Par exemple, 1000 pool serait créé pour la boucle
for(i=0;i<1000;i++) {
 NSString * string=[NSString stringWithFormat:... ];
 ...
}
Cela me semble impossible.
De même, pour une unité plus grande, une méthode ou une boucle d'événements : c'est trop ou pas assez, c'est au programmeur de décider si il veut le faire ou pas.
Ce qui est possible (voire probable) c'est qu'à la fin de la gestion d'un événement, il y ait un drain exécuté sur le pool concerné.
Donc non, il ne faut pas s'affranchir de cette contrainte
Les objets partagés doivent être des objets alloués par la voie normale !
Je n'ai jamais dit que chaque scope devait avoir un pool (encore heureux !) par contre, si ta boucle d'itération est très consommatrice de mémoire autoreleased, utile uniquement pour une itération, oui elle doit comporter un NSAutoreleasePool !
Encore une fois, le drain c'est que pour Obj-C 2.0 on parle d'un principe général là ...
(et si la doc n'a pas été mise à jour, c'est que ça doit fonctionner pareil...)
À bien lire et relire...
Schlum explique comment sont censés être utilisés les AutoreleasePool. Il doit effectivement y en avoir au moins un par thread. (cf. la documentation de Cocoa, comme detachDrawingThread:toTarget:withObject:).
Après, il est aussi possible de faire n'importe quoi avec un langage en mélangeant les objets entre les autorelease pools, mais je n'en vois pas l'intérêt. (c'est d'ailleurs une des difficultés que règlent en partie les fameuses properties de Obj-C 2.0)
Effectivement, ils ne sont pas créés tous seuls, mais rien n'empêche d'écrire
Oui, c'est ce qu'on dit : un autoreleasePool est créé à chaque runloop.
Et quand tu parles d'aléatoire : oui, l'ordre des instructions de deux threads concurrents sont plus ou moins aléatoires, mais au sein d'un thread, la gestion de la mémoire n'est pas plus aléatoire qu'ailleurs. C'est un autre débat.
+
Chacha
Le drain existait avant, forcément, il n'était pas documenté, c'est tout.
Je ne vois pas le rapport avec le fait qu'on cherche à savoir le fonctionnement arrière des applications.
Je ne cherche pas à savoir comment utiliser un autoreleasepool, je me pose des questions sur la durée de vie de l'allocation d'une zone mémoire quand sans avoir créé un seul pool, je fais un autorelease sur une variable.
Un peu plus haut je présente deux modèles possibles, l'un de libération par un pthread, pas du tout objective-C, et un autre par une méthode de vidage de tampon comme on peut le rencontrer classiquement en C.
La réponse et très simple et expliquée dans la doc :
- Warning d'erreur
- Leak
Quant à drain, non il n'existait même pas en non documenté
Cela existait forcément, peut-être sous un autre nom, pour vider le pool sans le détruire.
Et ce n'était pas documenté.
Confère ce post
Je pense que c'était en préparation pour 10.5...
Pourquoi voudrais-tu vider le pool sans le détruire ?
L'utilisation de NSAutoreleasePool ne prévoyait pas cette utilisation...
Les seuls gérés par Cocoa sont ceux des boucles d'événements, créés au début et détruits à la fin ; le reste est géré par l'utilisateur.
Où est la surprise là dedans ? ???
C'est donc le même pool qui est utilisé , et vidé plusieurs fois comme le breakpoint posé sur la méthode drain le montre.
C'est parce qu'avec Obj-C 2.0, ils ont dû remplacer la destruction / création par un drain sur celui du thread, au même niveau, vala tout ???
Si à chaque événement un pool était créé, cela se verrait dans Instruments > Object Alloc
Pour moi un pool global est créé au lancement de l'application, et peut-être un nombre limité d'autres pools pour différents détails ou threads non créés par le programme mais nécessaires au bon fonctionnement de l'appli. Et quand on fait autorelease, sans avoir créé son propre pool, la variable est inscrite , "marked" dit Hillegass, comme susceptible de recevoir un release dans un futur "imprécis".
Ben oui, mais je me tue à le dire depuis je ne sais combien de lignes