2010-01-07 6 views
2
#import <Foundation/Foundation.h> 

int main (int argc, char const *argv[]) 
{ 
    SampClass *obj=[[SampClass alloc] init]; 
    [obj release]; 
    NSLog(@"%i", [obj retainCount]); 
    return 0; 
} 

Pourquoi cela donne retainCount de 1, alors qu'il devrait être 0Gestion de la mémoire en Objective-C

Répondre

9

Ne pas appeler retainCount.

Pas même dans le code de débogage. Et surtout pas quand vous essayez d'apprendre comment fonctionne la gestion de la mémoire de Cocoa.

Le nombre absolu de rétention d'un objet n'est pas sous votre contrôle. Souvent, la valeur sera assez inattendue.Il peut y avoir un certain nombre de caches, d'allocations statiques (comme des NSStrings constants) ou d'autres détails d'implémentation interne dans des frameworks qui font que le nombre de retain d'un objet reste différent de ce que vous attendez.

Le nombre de rétention d'objets doit être considéré entièrement en termes de deltas. Si vous augmentez le nombre de retenue, vous doit le diminuer quelque part si vous souhaitez que l'objet soit libéré. Période. Fin de l'histoire.

Essayer de compter les chiffres en chiffres absolus ne fera qu'entraîner confusion et gaspillage d'heures. Le Cocoa Memory Management Guide explique assez bien cela.

0

Parce que l'objet a été désallouée avant votre appel NSLog.

Je suppose que la libération est mis en œuvre quelque chose comme ce qui suit:

 
if(retainCount==1) [self dealloc]; 
else retainCount--; 

et vous accédez illégalement l'objet désalloué.

Mise à jour: trouvé ces questions dont les réponses devraient vous éclairer davantage: here et here.

+1

Si 'release' était implémenté de cette façon,' obj' pourrait être désalloué plus d'une fois. – mouviciel

+0

@mouviciel uniquement si vous lui envoyez trop de messages, ce qui n'est pas le cas (sans tenir compte des problèmes de multithreading). J'essayais juste d'expliquer pourquoi l'exemple de SVA imprime 1. Mais comme l'objet est désalloué, il n'est pas vraiment possible de supposer quoi que ce soit sur son contenu. –

0

L'objet est désalloué mais une fois que l'objet a été placé pour conserver le compte 0, tous les appels de méthode risquent de renvoyer des valeurs périmées.

Si vous compilez et exécutez sur 32 bits, vous va obtenir une erreur (un message envoyé à retainCount objet libéré = 0x ...).

Je devine que le temps d'exécution 64 bits (option de compilation par défaut sur Leopard) ne recueille pas des objets aussi agressivement que le moteur d'exécution 32 bits afin que votre appel à retainCount ne provoque pas une erreur.

Pour vérifier que vous objet est en effet dealloced, mettre en œuvre dealloc pour vos SampClass:

- (void) dealloc 
{ 
    NSLog(@"Dealloc"); 
    [super dealloc]; 
} 

modifier plus tard: Comme je le pensais, la différence de comportement entre 32 et 64 bits lors de l'appel d'une méthode sur un objet libéré provient du runtime et non un comportement indéfini. En 32 bits, une fois qu'une classe est libérée, le pointeur isa est basculé vers une classe spéciale qui permet d'intercepter les messages sur les objets libérés. Cela n'arrive pas en 64 bits. source pertinente est objc-class.m:

#if !__OBJC2__ 
    // only clobber isa for non-gc 
    anObject->isa = _objc_getFreedObjectClass(); 
#endif 
+1

Cela n'a aucun sens. Il n'est pas question de «collection agressive» dans le code compté par référence - si vous libérez, et c'est la version finale équilibrée, l'objet est libéré. Pas plus tard, maintenant. –

+0

@Graham - Je ne peux pas expliquer le fait qu'en 64 bits, le dealloc sur l'objet est appelé, et pourtant je peux toujours appeler retainCount dessus. Ma seule supposition est que * free * n'est pas appelé sur l'objet mais plutôt l'objet est ajouté à un pool "free later". – diciu

+1

Que fait 'free'? Est-ce que ça garantit de changer le pointeur 'isa' d'un objet désalloué? Probablement pas; Si vous tentez d'envoyer un message à un objet désalloué, le moteur d'exécution peut voir n'importe quelle obstruction, y compris le dernier état de l'objet dans cet emplacement de mémoire. Cela ne le rend pas juste, probable, ou qui en vaut la peine. –

1

Il n'y a pas question de ce retainCount devrait dans votre code, vous ne devriez pas être l'appeler. S'appuyer sur le résultat de la messagerie d'un objet désalloué n'est pas une bonne idée. Voilà ce qui arrive quand je copie votre code et l'exécuter avec l'un des (nombreux) caractéristiques conservent-compte-débogage des cadres:

heimdall:~ leeg$ pbpaste | sed s/SampClass/NSObject/g > fubar.m 
heimdall:~ leeg$ cc -o fubar -framework Foundation fubar.m 
heimdall:~ leeg$ NSZombieEnabled=YES ./fubar 
2010-01-07 13:40:10.477 fubar[871:903] *** -[NSObject retainCount]: message sent to deallocated instance 0x10010d8f0 
Trace/BPT trap