10
votes

Où est le comptage de retenue stocké pour NsObjects dans l'objectif c

Je suis curieux de savoir comment conserver / relâcher les travaux en interne. Sur le visage, il semble qu'il y ait un entier associé à chaque instance d'un NsObject , qui augmente et diminuée lorsque vous appelez -Retain et -Release , respectivement.

Mais Jetez un coup d'oeil à NsObject , la seule variable d'instance utilisée est la variable ISA , pour déterminer son type de classe.

Alors, où sont conserver les comptes pour des objets individuels stockés? Pas que je vais me battre avec elle, mais juste pour ma propre édification.

est-il stocké avec le NsObject , mais caché dans certains détails de la mise en œuvre de l'objectif C? Si oui, cela semble être un mauvais design pour moi. Un devrait être en mesure de créer sa propre classe racine et de gérer leur propre compte de retenue / déverrouillage de la même manière (pas que c'est une bonne idée - il faudrait avoir un très bonne raison de ne pas utiliser nsobject ).


2 commentaires

WHENOUSERETAINECOUNT.COM


Lorsque nous parlons d'objets, elle devrait parfaitement parler de Boîtes noires , ce qui signifie que nous ne devrions pas nous soucier de Les détails des implémentations mais sur les interfaces. Vous proposez que Apple devait nous donner les détails de retenir le comptage, mais je dis avec la définition de l'interface que nous avons juste la bonne quantité de données que nous aurions besoin de la recréer. Nous avons kown, nous devons mettre en œuvre -Retain , -Release , -DeAlloc , ... pour recréer la gestion de la mémoire NSOBJETCS - mais nous sommes libres de le faire Qui a-t-il de mieux pour nous.


5 Réponses :


2
votes

Cela ne sonne pas comme ça, mais juste au cas où ... si vous envisagez d'utiliser Conserver le nombre directement, ne .

En ce qui concerne les détails de la mise en œuvre, les sessions à la WWDC 2011 ont mentionné que, sous ARC, la majeure partie de la mise en œuvre du comptage de référence s'est déplacée dans l'OBJC Runtime. source pour cela est disponible , afin que vous puissiez découvrir vous-même Comment ça fonctionne. Pour le comptage de référence manuelle, une grande partie des comportements de l'OBJC sont reproduits dans la base de la fondation et de la libdispatch, qui sont également open source - si vous souhaitez mettre en œuvre un système similaire vous-même, ceux-ci pourraient s'avérer éducatif.

En général, il s'agit d'un détail de mise en œuvre pour la même raison que beaucoup de choses sont les suivantes: l'encapsulation est une bonne politique, en particulier pour les fournisseurs-cadres. Vous ne voulez pas les utilisateurs d'un cadre en fonction des détails de la mise en œuvre, car vous ne pouvez pas modifier votre implémentation sans casser leur code.


0 commentaires

7
votes

Nous ne savons pas exactement comment les données sont stockées, mais nous pouvons exclure quelques options:

Variables de mise en œuvre privées H1>

Nous pouvons l'exclure, simplement parce que lorsque nous iTertons à travers les ivars de la classe NsObject code>, nous ne voyons qu'un seul: isa code>, comme indiqué dans ce programme: p> xxx pré>

et note que Même des propriétés de mise en œuvre privées existent dans la classe METDATA. P>

propriétés privées h1>

Nous pouvons également l'exclure, car même les propriétés privées sont exposées dans les métadonnées de classes, comme indiqué par l'exemple suivant. , il n'y a pas de propriétés pour la classe NsObject code> Classe: p> xxx pré>

objets associés h1>

Celui-ci est très difficile à exclure, Comme il n'y a pas de façons directes d'obtenir une liste de tous les objets associés. Cependant, étant donné que le concept d'objets associés est très nouveau et que le comptage de référence existe depuis toujours, je dis que cela n'est pas très probable. P>

CoreFoundation structure-mangling h1>

c'est mon meilleure estimation. Lorsque vous créez un NsObject, il s'agit d'une structure dans les coulisses. Que dire que la représentation de données NsObject réelle est quelque chose comme ceci: p> xxx pré>

puis, lorsqu'un objet est créé: p>

id object_createInstance(...)
{
    CFObjectRef object = malloc(sizeof(struct CFObject));

    ...

    return (id) (object + sizeof(object->retainCount));
}

int object_retainCount(id self)
{
    CFObjectRef asObject = (CFObjectRef) (self - sizeof(asObject->retainCount));
    return asObject->retainCount;
}


1 commentaires

Excellente réponse qui est également utile pour d'autres choses!



15
votes

L'emplacement de stockage du comptage de retenue dépend à la fois du temps d'exécution utilisé et de la mise en œuvre de la classe.

Pour l'exécution de l'objectif-C Apple, vous pouvez comprendre beaucoup en creuser dans Le code source de l'exécution de l'objectif-C .

Par exemple, si vous utilisez ARC (et je pense même si vous n'êtes pas), le nombre de références pour la plupart des objets sont stockés dans des tables de hachage. Regardez la fonction _OBJC_ROOTETAIN dans Runtime / objc-arr.mm . Je ne sais pas exactement pourquoi ils l'ont fait. Peut-être que c'est un moyen de conserver des comptes pour un meilleur comportement de cache (qui est important sous ARC, car l'ARC ajuste de retenir les comptes plus souvent que le code non arc ne le fait généralement pas).

Cependant, certaines classes remplacent conservent et des méthodes associées et stockent le nombre de retenons ailleurs. Par exemple, lors du débogage d'une fuite de mémoire, j'ai découvert que Calayer le fait. Au lieu d'utiliser le mécanisme de comptage normal de retenue normal de l'exécution, un Calayer stocke son compte de retenue dans un objet de mise en œuvre privé C ++. Ceci est plutôt frustrant car cela signifie que l'instrument d'allocations d'instruments ne se connecte pas conserve et des versions de calayer .


2 commentaires

Pour ajouter à cette question - une raison possible est que la classe NskonStantsTring doit avoir une mise en page très spécifique (voir ICI ) qui n'inclut pas un ivar de retenueCount. Alors que NSCONSTANTSTRING est une sous-classe de Nstring, qui est une sous-classe de NsObject, cela signifie que s'ils donnaient à NsObject un ivar supplémentaire, ils devraient construire la classe NskonStatifs à partir de zéro, essentiellement à partir d'une autre classe de base. Ceci est juste une raison, je suis sûr qu'il y a d'autres (meilleurs).


@Plpiper en fait, __ NSCFCONSTANTSTANTRING simplifie simplement retenir , libérant et autorelease comme no-ops. Essayez Disass -n '- [__ NSCFCONSTANTSTRING CONSERVEZ]' dans le débogueur. Il remplit également retentaincount pour renvoyer ~ 0 (sur 32 bits) ou ~ 0UL >> 4 (sur 64 bits), et il A un jeu de bits d'indicateur qui indique cfgetretaincount pour renvoyer une de ces valeurs.



0
votes

Je ne sais pas si cela serait pertinent, mais j'ai trébuché sur le blog post sur la mise en œuvre des messages d'ordre supérieur dans l'objectif-c. L'auteur implémente l'objet HOM en tant que classe racine (c'est-à-dire non hérité de NsObject) et la mise en oeuvre ressemble à ceci: xxx pré>

puis les méthodes de gestion du comptage de retenue sont implémentées comme ceci: p>

- (id)retain {
    __sync_add_and_fetch(&retainCount, 1);
    return self;
}

- (id)autorelease {
    [NSAutoreleasePool addObject:self];
    return self;
}

- (void)release {
    if (__sync_sub_and_fetch(&retainCount, 1) == 0) {
        [methodSignatureForSelector release];
        [forward release];
        object_dispose(self);
    }
}


0 commentaires

0
votes

Pour les aperçus d'addition, consultez http://www.mikeash.com/pyblog/friday-qa-2011-09-16- -2011-09-16-Lets-build-reference-counting.html , où Mike Ash explore une autre implémentation comme la seule Apple utilise .


0 commentaires