web-dev-qa-db-fra.com

Quel type de fuite le comptage automatique de références dans Objective-C ne permet-il pas d'éviter ou de minimiser?

Sur les plates-formes Mac et iOS, les fuites de mémoire sont souvent causées par des pointeurs non publiés. Traditionnellement, il a toujours été de la plus haute importance de vérifier vos allocations, copies et retenues pour vous assurer que chacune a un message de sortie correspondant.

La chaîne d'outils fournie avec Xcode 4.2 introduit le comptage automatique de références (ARC) avec la dernière version du compilateur LLVM , qui élimine totalement ce problème en obligeant le compilateur à gérer sa mémoire pour vous. C’est plutôt cool, cela permet de gagner beaucoup de temps de développement inutile et banal et d’éviter de nombreuses fuites de mémoire négligentes, faciles à corriger, avec un bon équilibre conservation/libération. Même les pools de libération automatique doivent être gérés différemment lorsque vous activez ARC pour vos applications Mac et iOS (car vous ne devriez plus allouer votre propre NSAutoreleasePools).

Mais qu'est-ce que d'autres fuites de mémoire est-ce que pas m'empêche de rester vigilant?

En prime, quelles sont les différences entre ARC sous Mac OS X et iOS et la récupération de place sous Mac OS X?

231
BoltClock

Le principal problème lié à la mémoire que vous devez toujours connaître est celui de la conservation des cycles. Cela se produit lorsqu'un objet a un pointeur fort sur un autre, alors que l'objet cible a un pointeur fort sur l'original. Même lorsque toutes les autres références à ces objets sont supprimées, elles se conservent et ne sont pas publiées. Cela peut aussi arriver indirectement, par une chaîne d'objets dont le dernier élément de la chaîne pourrait faire référence à un objet antérieur.

C’est pour cette raison que les qualificateurs de propriété __unsafe_unretained et __weak existent. Le premier ne conservera aucun objet pointé vers lui, mais laisse ouverte la possibilité que cet objet disparaisse et qu'il pointe vers un mauvais souvenir, tandis que le second ne conserve pas l'objet et se met automatiquement à zéro lorsque sa cible est désallouée. __weak est généralement préféré sur les plates-formes qui le prennent en charge.

Vous utiliseriez ces qualificateurs pour des éléments tels que les délégués, lorsque vous ne voulez pas que l'objet conserve son délégué et puisse éventuellement conduire à un cycle.

La gestion des objets Core Foundation et la mémoire allouée à l'aide de malloc() pour des types tels que char* constituent un autre problème important lié à la mémoire. ARC ne gère pas ces types, mais uniquement les objets Objective-C. Vous devrez donc vous en occuper vous-même. Les types de base de base peuvent être particulièrement difficiles, car ils doivent parfois être reliés aux objets Objective-C correspondants, et inversement. Cela signifie que le contrôle doit être transféré d'ARC en alternance entre les types CF et Objective-C. Quelques mots-clés liés à ce pontage ont été ajoutés, et Mike Ash a une excellente description des différents cas de pontage dans sa longue écriture dans ARC .

De plus, il existe plusieurs autres cas moins fréquents, mais toujours potentiellement problématiques, dans lesquels la spécification publiée entre dans les détails.

Une grande partie du nouveau comportement, basé sur la conservation des objets tant qu’il existe un pointeur fort, est très similaire à la récupération de place sur Mac. Cependant, les bases techniques sont très différentes. Plutôt que d'avoir un processus de ramasse-miettes qui s'exécute à intervalles réguliers pour nettoyer les objets auxquels on ne fait plus allusion, ce style de gestion de la mémoire repose sur les règles rigides de conservation/libération que nous devons tous respecter dans Objective-C. 

ARC prend simplement en charge les tâches de gestion de la mémoire répétitives que nous avons eues pendant des années et les transfère au compilateur afin que nous n'ayons plus à nous en soucier. De cette façon, vous ne rencontrez pas les problèmes d'arrêt ni les profils de mémoire en dents de scie rencontrés sur les plates-formes ramassées. J'ai expérimenté ces deux applications dans mes applications Mac collectées et je suis impatient de voir comment elles se comportent sous ARC.

Pour plus d'informations sur la récupération de place par rapport à ARC, voir cette réponse très intéressante de Chris Lattner sur la liste de diffusion Objective-C , où il répertorie de nombreux avantages d'ARC par rapport à la récupération de place Objective-C 2.0. J'ai rencontré plusieurs des problèmes du GC qu'il décrit.

260
Brad Larson

ARC ne vous aidera pas avec de la mémoire non ObjC, par exemple si vous malloc() quelque chose, vous devez toujours le free().

ARC peut être trompé par performSelector: si le compilateur ne peut pas comprendre ce qu'est le sélecteur (le compilateur générera un avertissement à ce sujet).

ARC générera également du code suivant les conventions de dénomination ObjC. Ainsi, si vous mélangez les codes ARC et MRC, vous obtiendrez des résultats surprenants si le code MRC ne fait pas ce que le compilateur pense que les noms promettent.

14
Stripes

J'ai rencontré des problèmes de mémoire dans mon application en raison des 4 problèmes suivants:

  1. Non invalidation des NSTimers lors du renvoi des contrôleurs de vue
  2. Oubli de supprimer des observateurs de NSNotificationCenter lors de la fermeture du contrôleur de vue.
  3. Garder de fortes références à soi-même par blocs.
  4. Utilisation de références fortes aux délégués dans les propriétés du contrôleur de vue

Heureusement, je suis tombé sur le blog suivant et j'ai pu le corriger: http://www.reigndesign.com/blog/debugging-retain-cycles-in-objective-c-four-llike-culprits/

7
Ed-E G

Xcode 9 est un excellent outil pour résoudre ce type de problèmes. Il s’appelle: "Graphique de mémoire de débogage" . En l’utilisant, vous pouvez localiser l’objet qui a fui par type de classe et voir clairement qui détient la référence forte en le relâchant à partir de là. résout votre problème. Il détecte également les cycles de la mémoire.

Voir plus d'informations sur son utilisation

0
Iliyan Kafedzhiev

ARC ne gérera pas non plus les types CoreFoundation. Vous pouvez les "ponter" (à l'aide de CFBridgingRelease()), mais uniquement si vous allez l'utiliser comme objet Objective-C/Cocoa. Notez que CFBridgingRelease ne décrémente que de 1 le nombre de conservations de CoreFoundation et le déplace vers le CRA de Objective-C.

0
MaddTheSane