2009-06-03 4 views
1

Je travaille sur un crash de l'iPhone un peu compliqué, et il semble que le coupable soit un NSString sorti prématurément. J'ai activé NSZombiesEnabled et je peux voir que NSString est un zombie au moment du crash. Cependant, je ne peux pas déterminer quand l'objet est libéré/désalloué - j'ai parcouru mon code en recherchant les messages de version envoyés à cet objet et j'ai défini des points d'arrêt à ces endroits, mais ils ne sont pas touchés. Je suppose qu'il s'agit peut-être d'un problème de threading ou d'autorelease étant donné sa nature intermittente, mais est-il possible de se connecter à l'exécution d'objectif-c via le débogueur Xcode pour indiquer le point exact où un objet est publié? Ou y a-t-il une meilleure façon de diagnostiquer ce problème?Comment savoir quand l'objet est envoyé message de libération?

Répondre

5

Si vous pouvez reproduire le crash dans le simulateur, vous pouvez utiliser l'outil malloc_history. (Il a une page de manuel.) Vous devez définir certaines variables d'environnement: normalement, je les configure via l'écran "Modifier l'exécutable actif" dans le volet Arguments, puis j'utilise les cases à cocher pour les activer/désactiver. Assurez-vous de les désactiver avant de déboguer sur l'appareil; Si activé, le programme essaiera d'écrire à /tmp que le sandbox n'autorise pas.

Je trouve cet outil combiné avec NSZombie me permet de traquer les erreurs alloc/prématurée-libération/accès-après-dealloc. Une fois que NSZombie signale l'accès à un objet désalloué, vous pouvez utiliser malloc_history pour déterminer quand l'objet a été alloué. Cela me met normalement sur la voie de l'élaboration où le problème est.

Un autre outil que j'ai trouvé inestimable est clang du projet LLVM. Il est encore en développement, mais ils produisent régulièrement des binaires pour MacOS-X qui me semblent assez stables. En particulier, il comprend la politique de gestion de la mémoire Cocoa. Son utilisation est aussi simple que:

% cd ${DIRECTORY_CONTAINING_XCODE_PROJECT} 
% xcodebuild clean 
% scan-build -V xcodebuild 

Cela va faire une génération complète de votre projet et de produire un rapport énumérant toutes les erreurs évidentes (y compris fiascos-comptage de référence) que l'outil trouve.

+0

Je seconde en utilisant CLang. Cela vous permettra souvent de trouver des choses que vous auriez pu manquer facilement, et beaucoup de choses trouvées peuvent entraîner des problèmes (pas tout) –

4

je ne pourrais pas être penser droit, mais avez-vous envisagé d'ajouter une version et dealloc sur votre classe

- (void) release 
{ 
    NSLog(@"Releasing"); 
    [super release]; 
} 
- (void) dealloc 
{ 
    NSLog(@"Deallocating"); 
    [super dealloc]; 
} 

Incorporer le commentaire de Ben Gotow d'utiliser une catégorie obj-c, vous vous retrouvez avec ceci:

@interface NSString (release) 
    -(void) release; 
@end 

@implementation NSString (release) 
-(void) release 
{ 
    NSLog(@"NSString Released!"); 
    [super release]; 
} 
@end 
+0

Devrait avoir mentionné, ceci est un NSString. – drewh

+0

Que diriez-vous de sous-classer NSString: http://developer.apple.com/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/doc/uid/20000154-397865 - la technique ci-dessus serait alors encore travailler. –

+2

Je crois que vous pourriez créer une catégorie Obj-C qui remplace les fonctions release et dealloc de NSString sans sous-classe ... Le sous-classement serait probablement très compliqué. –

0

Pourriez-vous implémenter dealloc() et mettre un point d'arrêt dedans? En regardant la trace de la pile à partir de ce point, vous devriez savoir où et comment elle est libérée.

+0

Ceci est un zombie NSString, donc je ne peux pas faire un point d'arrêt dans dealloc. – drewh

2

vous pouvez dire au fournisseur de dtrace de déclencher votre sonde chaque fois que -[NSString release] est appelé, mais cela impliquera un petit hackery méchant. Les NSStrings ne sont pas réellement des NSStrings mais sont toutes des sous-classes, en raison de la façon dont la classe est implémentée en tant que cluster de classe. Maintenant, cela ne nous gênera pas; ce sera est que NSString n'a pas son propre -release :-). Vous pouvez cependant fournir le vôtre dans une catégorie.

Vous pouvez également indiquer à quelle instance de NSString va se casser, vous pouvez simplement définir un point d'arrêt conditionnel sur -[NSObject dealloc] avec self==myInstance.

2

Une autre façon de procéder.Assurez-vous d'activer NSZombie afin qu'il indique l'adresse mémoire de l'objet qui obtient la version supplémentaire. Ensuite, exécutez avec Performance Tool-> Allocations d'objets. Cela amènera des instruments. Regardez le journal de la console fourni par Xcode organizer. Une fois que vous obtenez le crash, recherchez l'adresse de la mémoire dans les instruments. Vous verrez l'historique complet de mallocs/libres sur cet objet, ainsi que des liens directement dans votre code.

Questions connexes