Commençons par retain
et release
; autorelease
est vraiment juste un cas spécial une fois que vous comprenez les concepts de base.
Dans Cocoa, chaque objet garde une trace du nombre de fois où il est référencé (en particulier, la NSObject
classe de base l'implémente). En appelant retain
un objet, vous lui dites que vous souhaitez augmenter son nombre de références de un. En appelant release
, vous dites à l'objet que vous le lâchez, et son nombre de références est décrémenté. Si, après l'appel release
, le nombre de références est maintenant nul, alors la mémoire de cet objet est libérée par le système.
La façon fondamentale dont cela diffère malloc
et free
est que tout objet donné n'a pas besoin de s'inquiéter de la panne d'autres parties du système parce que vous avez libéré la mémoire qu'ils utilisaient. En supposant que tout le monde joue et retient / libère selon les règles, lorsqu'un morceau de code conserve puis libère l'objet, tout autre morceau de code référençant également l'objet ne sera pas affecté.
Ce qui peut parfois prêter à confusion, c'est de connaître les circonstances dans lesquelles vous devez appeler retain
et release
. Ma règle générale est que si je veux m'accrocher à un objet pendant un certain temps (s'il s'agit d'une variable membre dans une classe, par exemple), je dois m'assurer que le nombre de références de l'objet me connaît. Comme décrit ci-dessus, le nombre de références d'un objet est incrémenté lors de l'appel retain
. Par convention, il est également incrémenté (mis à 1, vraiment) lorsque l'objet est créé avec une méthode "init". Dans l'un ou l'autre de ces cas, il est de ma responsabilité de faire appel release
à l'objet lorsque j'en ai fini avec lui. Sinon, il y aura une fuite de mémoire.
Exemple de création d'objet:
NSString* s = [[NSString alloc] init]; // Ref count is 1
[s retain]; // Ref count is 2 - silly
// to do this after init
[s release]; // Ref count is back to 1
[s release]; // Ref count is 0, object is freed
Maintenant pour autorelease
. Autorelease est utilisé comme un moyen pratique (et parfois nécessaire) de dire au système de libérer cet objet après un certain temps. Du point de vue de la plomberie, lors de l' autorelease
appel, le thread actuel NSAutoreleasePool
est alerté de l'appel. Le NSAutoreleasePool
sait maintenant qu'une fois qu'il obtient une opportunité (après l'itération courante de la boucle d'événement), il peut appeler release
l'objet. De notre point de vue en tant que programmeurs, il prend soin de release
nous appeler , donc nous n'avons pas à le faire (et en fait, nous ne devrions pas).
Ce qui est important à noter, c'est que (encore une fois, par convention) toutes les méthodes de classe de création d'objet renvoient un objet publié automatiquement. Par exemple, dans l'exemple suivant, la variable «s» a un nombre de références de 1, mais une fois la boucle d'événements terminée, elle sera détruite.
NSString* s = [NSString stringWithString:@"Hello World"];
Si vous voulez vous accrocher à cette chaîne, vous devez l'appeler retain
explicitement, puis explicitement release
lorsque vous avez terminé.
Considérez le morceau de code suivant (très artificiel), et vous verrez une situation où autorelease
est nécessaire:
- (NSString*)createHelloWorldString
{
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
// Now what? We want to return s, but we've upped its reference count.
// The caller shouldn't be responsible for releasing it, since we're the
// ones that created it. If we call release, however, the reference
// count will hit zero and bad memory will be returned to the caller.
// The answer is to call autorelease before returning the string. By
// explicitly calling autorelease, we pass the responsibility for
// releasing the string on to the thread's NSAutoreleasePool, which will
// happen at some later time. The consequence is that the returned string
// will still be valid for the caller of this function.
return [s autorelease];
}
Je me rends compte que tout cela est un peu déroutant - à un moment donné, cependant, il cliquera. Voici quelques références pour vous lancer:
- Introduction d' Apple à la gestion de la mémoire.
- Cocoa Programming for Mac OS X (4e édition) , par Aaron Hillegas - un livre très bien écrit avec beaucoup de bons exemples. Cela se lit comme un tutoriel.
- Si vous plongez vraiment, vous pouvez vous rendre au Big Nerd Ranch . Il s'agit d'un centre de formation géré par Aaron Hillegas - l'auteur du livre mentionné ci-dessus. J'ai suivi le cours d'introduction au cacao il y a plusieurs années, et c'était une excellente façon d'apprendre.
NSString* s = [[NSString alloc] initWithString:@"Hello World"];
renvoie un objet libéré automatiquement (tel que vous l'écrivez), pourquoi dois-je faire unreturn [s autorelease];
et le définir à nouveau sur "autorelease" et pas seulementreturn s
?[[NSString alloc] initWithString:@"Hello World"]
ne retournera PAS d'objet publié automatiquement. Chaque fois qu'ilalloc
est appelé, le nombre de références est défini sur 1 et il est de la responsabilité de ce code de s'assurer qu'il est libéré. L'[NSString stringWithString:]
appel, d'autre part, ne retourne un objet autoreleased.Si vous comprenez le processus de conservation / libération, alors il y a deux règles d'or qui sont "duh" évidentes pour les programmeurs Cocoa établis, mais qui sont malheureusement rarement énoncées clairement pour les nouveaux venus.
Si une fonction qui renvoie un objet a
alloc
,create
oucopy
dans son nom, alors l'objet est à vous. Vous devez appeler[object release]
lorsque vous en avez terminé. OuCFRelease(object)
, s'il s'agit d'un objet Core-Foundation.S'il n'a PAS un de ces mots dans son nom, alors l'objet appartient à quelqu'un d'autre. Vous devez appeler
[object retain]
si vous souhaitez conserver l'objet après la fin de votre fonction.Vous seriez bien servi de suivre également cette convention dans les fonctions que vous créez vous-même.
(Nitpickers: Oui, il y a malheureusement quelques appels d'API qui font exception à ces règles mais ils sont rares).
la source
Si vous écrivez du code pour le bureau et que vous pouvez cibler Mac OS X 10.5, vous devriez au moins envisager d'utiliser le garbage collection Objective-C. Cela simplifiera vraiment la plupart de votre développement - c'est pourquoi Apple a tout mis en œuvre pour le créer en premier lieu et le faire fonctionner correctement.
Quant aux règles de gestion de la mémoire lorsque vous n'utilisez pas GC:
+alloc/+allocWithZone:
,+new
,-copy
ou-mutableCopy
ou si vous-retain
un objet, vous prenez la propriété de celui - ci et doit veiller à ce qu'il soit envoyé-release
.-release
.-release
vous pouvez l'envoyer vous-même, ou vous pouvez envoyer l'objet-autorelease
et le pool de libération automatique actuel l'enverra-release
(une fois par réception-autorelease
) lorsque le pool est vidé.Il
-autorelease
est généralement utilisé pour garantir que les objets vivent pendant toute la durée de l'événement en cours, mais sont nettoyés par la suite, car il existe un pool de libération automatique qui entoure le traitement des événements de Cocoa. Dans Cocoa, il est beaucoup plus courant de renvoyer des objets à un appelant qui sont libérés automatiquement que de renvoyer des objets que l'appelant lui-même doit libérer.la source
Objective-C utilise le comptage de références , ce qui signifie que chaque objet a un nombre de références. Lorsqu'un objet est créé, il a un nombre de références de "1". En termes simples, lorsqu'un objet est référencé (c'est-à-dire stocké quelque part), il est "retenu", ce qui signifie que son nombre de références est augmenté de un. Lorsqu'un objet n'est plus nécessaire, il est «libéré», ce qui signifie que son nombre de références est diminué de un.
Lorsque le nombre de références d'un objet est égal à 0, l'objet est libéré. Il s'agit du comptage de référence de base.
Pour certaines langues, les références sont automatiquement augmentées et diminuées, mais objective-c ne fait pas partie de ces langues. Ainsi, le programmeur est responsable de la conservation et de la libération.
Une manière typique d'écrire une méthode est:
Le problème de devoir se souvenir de libérer toutes les ressources acquises à l'intérieur du code est à la fois fastidieux et sujet aux erreurs. Objective-C introduit un autre concept visant à rendre cela beaucoup plus facile: les pools de lancement automatique. Les pools de libération automatique sont des objets spéciaux installés sur chaque thread. Il s'agit d'une classe assez simple, si vous recherchez NSAutoreleasePool.
Lorsqu'un objet reçoit un message "autorelease" qui lui est envoyé, l'objet recherchera tous les pools de libération automatique se trouvant sur la pile pour ce thread actuel. Il ajoutera l'objet à la liste en tant qu'objet auquel envoyer un message de «libération» à un moment donné dans le futur, ce qui se produit généralement lorsque le pool lui-même est libéré.
En prenant le code ci-dessus, vous pouvez le réécrire pour qu'il soit plus court et plus facile à lire en disant:
Étant donné que l'objet est libéré automatiquement, nous n'avons plus besoin d'appeler explicitement "release" dessus. C'est parce que nous savons que certains pools de libération automatique le feront pour nous plus tard.
Espérons que cela aide. L'article de Wikipedia est assez bon sur le comptage des références. Pour plus d'informations sur les pools de libération automatique, cliquez ici . Notez également que si vous construisez pour Mac OS X 10.5 et versions ultérieures, vous pouvez demander à Xcode de créer avec le ramasse-miettes activé, ce qui vous permet d'ignorer complètement la conservation / la libération / la libération automatique.
la source
Joshua (# 6591) - Le contenu de la collecte des ordures dans Mac OS X 10.5 semble plutôt cool, mais n'est pas disponible pour l'iPhone (ou si vous voulez que votre application fonctionne sur les versions antérieures à 10.5 de Mac OS X).
De plus, si vous écrivez une bibliothèque ou quelque chose qui pourrait être réutilisé, l'utilisation du mode GC empêche toute personne utilisant le code d'utiliser également le mode GC, donc si je comprends bien, toute personne essayant d'écrire du code largement réutilisable a tendance à opter pour la gestion mémoire manuellement.
la source
Comme toujours, lorsque les gens commencent à essayer de reformuler le matériel de référence, ils se trompent presque invariablement ou fournissent une description incomplète.
Apple fournit une description complète du système de gestion de la mémoire de Cocoa dans le Guide de programmation de la gestion de la mémoire pour Cocoa , à la fin duquel se trouve un résumé bref mais précis des règles de gestion de la mémoire .
la source
Je n'ajouterai pas à la spécificité de retenir / publier autre que vous voudrez peut-être penser à perdre 50 $ et à obtenir le livre Hillegass, mais je suggère fortement d'utiliser les outils Instruments très tôt dans le développement de votre application (même votre Premier!). Pour ce faire, exécutez-> Commencez avec des outils de performance. Je commencerais par Leaks qui n'est qu'un des nombreux instruments disponibles mais qui vous aidera à vous montrer quand vous avez oublié de sortir. La quantité d'informations qui vous sera présentée est décourageante. Mais consultez ce tutoriel pour vous lever et aller vite:
TUTORIEL CACAO: RÉPARER LES FUITES DE MÉMOIRE AVEC DES INSTRUMENTS
En fait, essayer de forcer les fuites pourrait être un meilleur moyen, à son tour, d'apprendre à les éviter! Bonne chance ;)
la source
Autorelease ne conserve pas l'objet. Autorelease le met simplement en file d'attente pour être publié plus tard. Vous ne voulez pas y avoir de déclaration de sortie.
la source
Ma collection habituelle d'articles sur la gestion de la mémoire Cocoa:
gestion de la mémoire cacao
la source
Un screencast gratuit est disponible sur le réseau iDeveloperTV
Gestion de la mémoire dans Objective-C
la source
La réponse de NilObject est un bon début. Voici quelques informations supplémentaires relatives à la gestion manuelle de la mémoire ( obligatoire sur l'iPhone ).
Si vous personnellement
alloc/init
un objet, il est livré avec un nombre de références de 1. Vous êtes responsable du nettoyage après lui quand il n'est plus nécessaire, soit en appelant[foo release]
ou[foo autorelease]
. release le nettoie tout de suite, tandis que l'autorelease ajoute l'objet au pool d'autelease, qui le libèrera automatiquement ultérieurement.autorelease est principalement pour lorsque vous avez une méthode qui a besoin de retourner l'objet en question ( vous ne pouvez donc pas le libérer manuellement, sinon vous retournerez un objet nul ) mais que vous ne voulez pas non plus le garder .
Si vous acquérez un objet où vous n'avez pas appelé alloc / init pour l'obtenir - par exemple:
mais vous voulez vous accrocher à cet objet, vous devez appeler [foo retenir]. Sinon, il est possible que cela obtienne
autoreleased
et que vous vous accrochiez à une référence nulle (comme dans l'stringWithString
exemple ci-dessus ). Lorsque vous n'en avez plus besoin, appelez[foo release]
.la source
Les réponses ci-dessus reprennent clairement ce que dit la documentation; le problème que rencontrent la plupart des nouvelles personnes, ce sont les cas sans papiers. Par exemple:
Autorelease : les documents indiquent qu'il déclenchera une version "à un moment donné dans le futur". QUAND?! Fondamentalement, vous pouvez compter sur l'objet jusqu'à ce que vous quittiez votre code dans la boucle d'événements système. Le système PEUT libérer l'objet à tout moment après le cycle d'événements en cours. (Je pense que Matt l'a dit plus tôt.)
Chaînes statiques :
NSString *foo = @"bar";
- devez-vous conserver ou libérer cela? Non, pourquoi pas...
La règle de création : si vous l'avez créée, vous en êtes propriétaire et vous êtes censé la publier.
En général, la façon dont les nouveaux programmeurs Cocoa se trompent est de ne pas comprendre quelles routines renvoient un objet avec un
retainCount > 0
.Voici un extrait de Règles très simples pour la gestion de la mémoire dans Cocoa :
La première puce dit: si vous avez appelé
alloc
(ounew fooCopy
), vous devez appeler la libération sur cet objet.La deuxième puce dit: si vous utilisez un constructeur pratique et que vous avez besoin que l'objet traîne (comme pour une image à dessiner plus tard), vous devez le conserver (puis le relâcher plus tard).
Le 3ème devrait être explicite.
la source
Beaucoup de bonnes informations sur cocoadev aussi:
la source
Comme plusieurs personnes l'ont déjà mentionné, l' Introduction à la gestion de la mémoire d' Apple est de loin le meilleur point de départ.
Un lien utile que je n'ai pas encore vu mentionné est la gestion pratique de la mémoire . Vous le trouverez au milieu des documents d'Apple si vous les lisez, mais cela vaut la peine de créer un lien direct. C'est un brillant résumé des règles de gestion de la mémoire avec des exemples et des erreurs courantes (essentiellement ce que les autres réponses tentent d'expliquer ici, mais pas aussi bien).
la source