编程知识 cdmana.com

IOS Underground Learning - Memory Management (Memory five areas, tiggedpointer, reference Count)

1.Disposition de la mémoire

Cinq partitions de mémoire: Stack area、Zone de gerbage、Zone globale、Région constante、Zone de code

ee0f152a7b524e6f8207f864b51a7589~tplv-k3u1fbpfcp-watermark.image.png

1.Cinq régions de mémoire

  1. Stack area(stack)

    • Caractéristiques

      • Stack est la structure de données du système,Le processus ou le thread correspondant est unique
      • La pile est une structure de données qui s'étend à une adresse basse
      • La pile est une zone de mémoire continue,Suivre la sortie arrière avancée(FILO)Principes
      • L'espace d'adresse de la pile estiOSAu milieu.0X7Au début
      • Les zones de pile sont généralement assignées au moment de l'exécution
    • Stockage du contenu

      • La zone de pile est automatiquement assignée et libérée par le compilateur,Utilisé principalement pour stocker des variables locales
      • Paramètres de la fonction,Par exemple, les paramètres cachés d'une fonction(id self,SEL _cmd
    • Avantages et inconvénients

      • Avantages:Parce que la pile est automatiquement assignée et libérée par le compilateur,Pas de fragment de mémoire,Donc rapide et efficace
      • Inconvénients:La taille de mémoire de la pile est limitée,Données rigides
      • iOSLa taille de la pile de fil primaire est1MB,Les autres fils principaux sont512KB,MACSeulement8M

    Valeur du paramètre de la fonction entrante 、 Variables locales déclarées dans le corps de la fonction, etc. , Libération automatique assignée par le compilateur , Généralement libéré après l'exécution de la fonction .(Attention!:Non comprisstaticVariables modifiées,static Signifie que la variable est stockée dans le monde entier /Zone statique)

    InThreading Programming GuideOui., Description de la taille de la mémoire ,Voir ci - dessous:

    image.png

  2. Zone de gerbage(heap)

    • Caractéristiques

      • Heap est une structure de données qui s'étend vers une adresse élevée
      • Le tas est une zone de mémoire discontinue , Similaire à la structure de la liste de liens (Facile à ajouter et à supprimer,Pas facile à consulter),Suivre le premier entré, premier sorti(FIFO)Principes
      • L'espace d'adresse du tas estiOSAu milieu.0x6Au début,La répartition de son espace est toujours dynamique
      • L'allocation de la zone du tas est généralement effectuée au moment de l'exécution.
    • Stockage du contenu

      • Les zones de tas sont assignées et libérées dynamiquement par le programmeur , Si le programmeur ne libère pas , Après la procédure , Peut être récupéré par le système d'exploitation
      • OCUtilisé dansallocOu utilisernewCréer de l'espace pour créer des objets
      • CUtilisé dans la languemalloccallocreallocEspace alloué,BesoinfreeRelease
    • Avantages et inconvénients

      • Avantages:Flexible et pratique, Large gamme d'adaptations des données
      • Inconvénients:Gestion manuelle requise,Lent.、Facile à créer des fragments de mémoire

    Lorsque l'accès à la mémoire en tas est nécessaire ,En général, vous devez d'abord lire l'adresse du pointeur dans la zone de pile à travers l'objet, Puis accédez à la zone du tas par l'adresse du pointeur .Parce que maintenantiOS Essentiellement utilisé ARC Pour gérer les objets , Il n'est donc pas nécessaire de libérer manuellement .

  3. Zone globale(Zone statique)(BSSParagraphes)

    • BSSParagraphesbss segment)Habituellement utilisé pour stocker des programmes qui ne sont pas initialisés ou dont la valeur initiale est0 Une zone de mémoire de la variable globale pour .BSSC'est l'anglais.Block Started by SymbolAbréviations.BSS Le segment appartient à une allocation de mémoire statique .

    • Section des données:Section des données(data segment)Il s'agit généralement d'une zone de mémoire utilisée pour stocker des variables globales initialisées dans un programme, Le segment de données appartient à une allocation de mémoire statique .

    • La zone globale est l'espace mémoire alloué au moment de la compilation ,IniOSLa moyenne est généralement0x1Au début,Pendant l'exécution du programme,Les données de cette mémoire existent toujours,Libéré par le système à la fin du programme,Stockage primaire

      • Variables globales et statiques non initialisées,C'est - à - dire:BSSZone(.bss
      • Variables globales et statiques initialisées,C'est - à - dire:Zone de données.data
    • Parstatic Les variables modifiées deviennent statiques , La mémoire de cette variable est générée par Global / Les zones statiques sont assignées au stade de la compilation , Et n'est attribué qu'une seule fois .

    • staticVous pouvez modifier les variables locales ou globales.

  4. Région constante(Section des données)

    • La zone constante est l'espace mémoire alloué au moment de la compilation ,IniOSLa moyenne est généralement0x1Au début, Libéré par le système à la fin du programme
    • Il s'agit généralement d'une zone de mémoire utilisée pour stocker des variables globales et statiques déjà initialisées dans un programme. Le segment de données appartient à une allocation de mémoire statique , Peut être divisé en segments de données en lecture seule et en segments de données en lecture - écriture . Constantes de chaîne, etc. , Oui dans un segment de données en lecture seule , Ne sera pas rappelé avant la fin du programme .
  5. Zone de code(Extrait de code)

    • La zone de code est le Code attribué par le temps de compilation qui est principalement utilisé pour stocker le temps d'exécution du programme, Le Code sera compilé en binaires et stocké en mémoire
    • La zone de code doit être protégée contre les modifications illégales au moment de l'exécution, Par conséquent, seules les opérations de lecture sont autorisées. , Ne pas autoriser l'écriture (Modifier)Fonctionnement—— C'est écrit. .
  • Supplément En plus de la zone mémoire ci - dessus , Le système conserve également une partie de la mémoire .

2. Vérification de la partition mémoire

Voici comment distinguer les différentes zones de mémoire par Code.

  1. Stack area

    Les codes de vérification sont les suivants: :

    - (void)testStack{
        NSLog(@"************Stack area************");
    
        // Stack area
        int a = 10;
        int b = 20;
        NSObject *object = [NSObject new];
    
        NSLog(@"a == \t%p",&a);
        NSLog(@"b == \t%p",&b);
        NSLog(@"object == \t%p",&object);
    
        NSLog(@"%lu",sizeof(&object));
        NSLog(@"%lu",sizeof(a));
    }
    Copier le Code

    Dans le code ci - dessus,abobject Sont des variables locales , Ces variables sont stockées dans la pile .Résultats des opérations:

    image.png

  2. Zone de gerbage

    Les codes de vérification sont les suivants: :

    - (void)testHeap{
        NSLog(@"************Zone de gerbage************");
        // Zone de gerbage
        NSObject *object1 = [NSObject new];
        NSObject *object2 = [NSObject new];
        NSObject *object3 = [NSObject new];
        NSLog(@"object1 = %@",object1);
        NSLog(@"object2 = %@",object2);
        NSLog(@"object3 = %@",object3);
        // Accès à---Par objet-> Adresse de la zone de stockage -> Pointeur avec zone de pile existante 
    }
    Copier le Code

    Le code ci - dessus crée trois variables , Les trois variables sont stockées dans la pile ,Ces variables stockent des pointeurs vers des objets dans la zone de tas. Voir la figure ci - dessous pour la structure de fonctionnement. :

    image.png

  3. Zone globale、Région constante

    Les codes de cas sont les suivants::

    int clA;
    int clB = 10;
    
    static int bssA;
    static NSString *bssStr1;
    static int bssB = 10;
    static NSString *bssStr2 = @"hello";
    static NSString *name = @"name";
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        NSLog(@"************Stack area************");
        int sa = 10;
        NSLog(@"bssA == \t%p",&sa);
        NSLog(@"************Zone globale************");
        NSLog(@"clA == \t%p",&clA);
        NSLog(@"bssA == \t%p",&bssA);
        NSLog(@"bssStr1 == \t%p",&bssStr1);
        NSLog(@"clB == \t%p",&clB);
        NSLog(@"bssB == \t%p",&bssB);
        NSLog(@"bssStr2 == \t%p",&bssStr2);
        NSLog(@"bssStr2 == \t%p",&name);
    }
    Copier le Code

    Dans le cas ci - dessus ,En imprimant l'adresse de la variable de la zone globale par rapport à la variable de la zone de pile,Voir la figure ci - dessous pour les résultats de fonctionnement.:

    image.png

2.TiggedPointerPetits objets

1. Qu'est - ce qu'un petit objet

Nous savons qu'un objet a besoin au moins 8Octets, Mais c'est un gaspillage de données. ,Par exemple,NSNumberNSDateNSString( Petite chaîne ).Alors...64Environnement binaire,IntroduitTagged PointerTechnique,Avec unPetits objets Pour stocker ces données . Exemple de chaîne ,Voir ci - dessous:

image.png

D'après le cas ci - dessus, ,str1Etstr4La différence entre,str1Le type deNSTaggedPointerString,Etstr4- Oui.__NSCFStringType. L'adresse de sortie de la console est également trouvée , Les adresses des autres zones de tas sont également très différentes :

image.png

2.Analyse de cas

Nous continuons à analyser les différences à travers des cas .

  • CAS1 image.png

  • CAS2 image.png

  • Résultats des opérations

    Exécuter les deux cas ci - dessus séparément , Que se passe - t - il? ?

    • CAS1Des erreurs seront signalées
    • CAS2Fonctionnement normal

    Debug Open View Assembly ,CAS1 Message d'erreur d'exécution ,Voir ci - dessous: image.png Journal des erreurs d'analyse , Mauvais accès à la mémoire ,Pourquoi??

  • Analyse des causes

    set La méthode est en fait une nouvelle valeur retain, Ancien release.Parce quenameStrModifier comme suit:nonatomic Donc C'est un thread dangereux. . Lorsque plusieurs fils accèdent simultanément , Cause multiple release,Donc ça va arriver Mauvais accès à la mémoire .

  • Comment le résoudre??

    Modifier comme suit: atomic Ou plus Verrouillage.

  • PourquoiCAS2 Ça marche. ?

    InCAS1Moyenne,Définir le point d'arrêt,Découvrez maintenantnameStrLe type de données est__NSCFString,Voir ci - dessous: image.png

    EtCAS2Moyenne,nameStrLe type de données estTiggedPointer,Voir ci - dessous: image.png

    Les objets normaux sont des pointeurs vers des adresses dans la mémoire tas,Alors...CAS1Mauvais accès à la mémoire en raison de l'accès multithreadé,EtTaggedPointerStocké dans une zone constante, Ne pas créer de mémoire . Lors de la libération d'objets ,PourTiggedPointer Type filtré ,Disons justeTiggedPointer Le type ne gère pas le nombre de références . Voir le code source ci - dessous :

    image.png

3.TiggedPointerAnalyse des principes

Nous rechargeons la classe _read_images La méthode a été explorée TiggedPointerContenu des aspects.Voir ci - dessous:

image.png

AdoptioninitializeTaggedPointerObfuscatorMéthodes,RéalisationTaggedPointer Initialisation du mélangeur de pointeurs , Voir la figure ci - dessous pour la mise en œuvre du code source :

image.png

C'est - à - dire, Dans le cas ci - dessus, ,Nous passons%pImprimerTaggedPointerObjet Contenu à l'adresse , Est le résultat de la conversion du pointeur par le mélangeur .

Recherche globaleobjc_debug_taggedpointer_obfuscator, Nous pouvons trouver des cibles TaggedPointerObjet Algorithme de codage et de décodage des pointeurs :

image.png

L'algorithme ci - dessus vous permet de découvrir , Le processus de codage est :

uintptr_t value = (objc_debug_taggedpointer_obfuscator ^ ptr);
Copier le Code

Le processus de décodage est :

value ^ objc_debug_taggedpointer_obfuscator;
Copier le Code

Algorithme de codage et de décodage trouvé ,Nous pouvons décoder l'adresse de sortie du petit objet, Obtenez le contenu de son pointeur original . Voir le processus ci - dessous :

image.png

Parmi eux**0xa000000000000621** C'est le résultat du décodage. . Que signifie cette adresse? ? C'est quelque chose que nous devons explorer. !!!

  • TaggedPointer Analyse du type de pointeur

    InTaggedPointer Dans le code source pertinent , J'ai trouvé le code suivant. :

    static inline bool 
    _objc_isTaggedPointer(const void * _Nullable ptr)
    {
        return ((uintptr_t)ptr & _OBJC_TAG_MASK) == _OBJC_TAG_MASK;
    }
    
    #if OBJC_SPLIT_TAGGED_POINTERS
    # define _OBJC_TAG_MASK (1UL<<63)
    Copier le Code

    Déterminer si un objet est TaggedPointerType, Via le pointeur d'objet &Allez._OBJC_TAG_MASK Et ensuite égal à _OBJC_TAG_MASKMoi - même.;Et celui - cimask C'est haut. 1,Le reste est0De64Nombre de chiffres.C'est - à - dire si l'adresse supérieure d'un objet est1, Est considéré comme un petit objet .

    L'analyse de cas est présentée ci - dessous. :

    image.png

    Par la structure de sortie du cas ci - dessus ,C'est presque certain., Élevé 0xaReprésentantNSString,0xbReprésentantNSNumber,0xeReprésentantNSDate. On va le restaurer. :

    • 0xa -> 1010
    • 0xb -> 1011
    • 0xe -> 1110

    On peut voir que les hauteurs sont toutes 1, Donc ce sont tous TaggedPointerType, C'est un petit objet. . Donc si vous enlevez le Haut 1, Le reste devrait être représenté. tag,C'est - à - dire::

    • 0xa -> 1010 -> 010 ReprésentationNSString
    • 0xb -> 1011 -> 011 ReprésentationNSNumber
    • 0xe -> 1110 -> 110 ReprésentationNSDate

    N'est - ce pas?? Voir le code source ci - dessous :

    image.png

    Lors du marquage de petits types d'objets ,C'est passé.objc_tag_index_tTypetag,Voirobjc_tag_index_tDéfinitions:

    #if __has_feature(objc_fixed_enum)  ||  __cplusplus >= 201103L
    enum objc_tag_index_t : uint16_t
    #else
    typedef uint16_t objc_tag_index_t;
    enum
    #endif
    {
        // 60-bit payloads
        OBJC_TAG_NSAtom            = 0, 
        OBJC_TAG_1                 = 1, 
        OBJC_TAG_NSString          = 2, 
        OBJC_TAG_NSNumber          = 3, 
        OBJC_TAG_NSIndexPath       = 4, 
        OBJC_TAG_NSManagedObjectID = 5, 
        OBJC_TAG_NSDate            = 6,
    
        // 60-bit reserved
        OBJC_TAG_RESERVED_7        = 7, 
    };
    Copier le Code
    • NSString = 2 -> 010
    • NSNumber = 3 -> 011
    • NSDate = 6 -> 110

    C'est exactement ce que nous pensions. ! L'adresse du type de petit objet contient le type . Où les valeurs sont - elles stockées? ?

  • TaggedPointerAnalyse de la valeur

    De même, nous introduisons un cas :

    image.png

    Dans le cas ci - dessus ,Nous pouvons trouver que le dernier bit du pointeur représente la longueur du petit objet. Où les valeurs sont - elles stockées? ?WWDC Dans les notes pertinentes , Si nécessaire, obtenir des valeurs à l'intérieur , Besoin de voir les binaires , Obtenir la valeur correspondante par bit . Le processus d'analyse est illustré dans la figure ci - dessous. :

    image.png

    Comme vous pouvez le voir ci - dessus , Le pointeur du petit objet contient le type d'objet ,Valeur de l'objet, Informations sur la longueur de l'objet .

  • Résumé

    En interprétant le code source et l'analyse de cas ,Nous envoyons de petits objets qui sont filtrés lors de l'opération de libération, Aucun processus de libération connexe ne sera effectué , Il est stocké dans une zone constante , Ne pas appliquer et libérer la mémoire , Beaucoup plus efficace !

3.Nombre de références

Nous savons que les solutions de gestion de la mémoire sont divisées en MRCEtARC, Mais quel que soit le plan, , Est le traitement du nombre de références , Ces méthodes concernent: :allocdeallocrealeaseretainretainCountautorealeaseAttendez..MRCEnvironnement, Nous devons appeler ces méthodes manuellement ,ARCEnvironnement, Le système nous appellera automatiquement. . Comment ces méthodes sont - elles mises en œuvre? ? Nous analysons étape par étape !

Examinons d'abord ,nonpointer isa, Champ de position de la structure utilisé ,Pourarm64ArchitectureEtx86Architecture Offre une offre différente Règles de configuration des champs de bits . Il comprend deux champs importants :has_sidetable_rcCompteur de référenceEtextra_rc Nombre de références d'objets .

Comment analyser leur relation? ,allocEtretainMéthodes! Dans les chapitres précédents, ,Déjà analyséallocProcessus de traitement,Terminé.isaCréation de;retain Le compte de référence de l'objet est également effectué ,En basretain La méthode commence l'analyse .

1.retainMéthodes

Trouverretain Source de mise en œuvre de la méthode :

image.png

Il appellerootRetainMéthodes,TrouverrootRetainSource d'implémentation pour:

image.png

Par interprétation préliminaire , La zone de la boîte rouge est le Code de base , Le contenu de cette section est analysé plus en détail ci - dessous. .

Le jugement a été porté au début de la méthode , L'objet courant est TaggedPointerType, C'est un petit objet. , S'il s'agit d'un petit objet, retourner directement sans traitement ,Les petits objets ne sont donc pas traités en termes de comptage des références, Pas besoin d'ouvrir et de libérer la mémoire , À compléter automatiquement par le système .

Indo...while En boucle isa Opérations liées au comptage des références ,Inwhile Dans l'énoncé de jugement ,AppelezStoreExclusive Méthodes pour compléter les anciens et les nouveaux isa Opération de remplacement de la comparaison , Sortie du cycle après succès .

En boucle, D'abord, jugez si ce n'est pas le cas. nonpointer isa, Pour traiter le hachage correspondant à l'objet SideTableNombre de références pour.Voir le code ci - dessous:

    if (slowpath(!newisa.nonpointer)) {
            ClearExclusive(&isa.bits);
            if (tryRetain) return sidetable_tryRetain() ? (id)this : nil;
            else return sidetable_retain(sideTableLocked);
    }
Copier le Code

Contenu du tableau de hachage , A été expliqué lors de l'analyse des références faibles :weakPrincipes de mise en œuvre et processus de destruction

Si vous relâchez isDeallocating,C'est le moment.isaDeextra_rcEthas_sidetable_rcTous.0, Le nombre de références n'a pas besoin d'être traité ,Le code source est le suivant::

    bool isDeallocating() {
        return extra_rc == 0 && has_sidetable_rc == 0;
    }
Copier le Code

Si aucun des éléments ci - dessus n'est satisfait , Alors ça va se passer. isaMoyenneextra_rc Fonctionnement des propriétés , C'est - à - dire ajouter au nombre de références 1, Sous différents cadres extra_rcOù?isa La position de ,Alors...RC_ONE Les valeurs des champs de bits sont également différentes .Voir le code ci - dessous:

    uintptr_t carry;
    newisa.bits = addc(newisa.bits, RC_ONE, 0, &carry);  //extra_rc++
Copier le Code

carryPour jugerextra_rc Le champ est - il entièrement stocké? , Si plein , Exécutez le code suivant :

    if (slowpath(carry)) {
            // newisa.extra_rc++ overflowed
            if (variant != RRVariant::Full) {
                ClearExclusive(&isa.bits);
                return rootRetain_overflow(tryRetain);
            }
            // Leave half of the retain counts inline and 
            // prepare to copy the other half to the side table.
            if (!tryRetain && !sideTableLocked) sidetable_lock();
            sideTableLocked = true;
            transcribeToSideTable = true;
            newisa.extra_rc = RC_HALF;
            newisa.has_sidetable_rc = true;
        }
Copier le Code

Dans le processus ci - dessus, si extra_rcPlein.,Oui.extra_rc La moitié de la capacité de stockage , Dans le tableau de hachage correspondant à l'objet . Voir le code ci - dessous :

    if (slowpath(transcribeToSideTable)) {

        // Copy the other half of the retain counts to the side  table.
        sidetable_addExtraRC_nolock(RC_HALF);
    }
    
    bool 
    objc_object::sidetable_addExtraRC_nolock(size_t delta_rc)
    {
        ASSERT(isa.nonpointer);
        SideTable& table = SideTables()[this];

        size_t& refcntStorage = table.refcnts[this];
        size_t oldRefcnt = refcntStorage;
        
        // isa-side bits should not be set here
        ASSERT((oldRefcnt & SIDE_TABLE_DEALLOCATING) == 0);
        ASSERT((oldRefcnt & SIDE_TABLE_WEAKLY_REFERENCED) == 0);

        if (oldRefcnt & SIDE_TABLE_RC_PINNED) return true;
        uintptr_t carry;
        size_t newRefcnt = 
            addc(oldRefcnt, delta_rc << SIDE_TABLE_RC_SHIFT, 0, &carry);

        if (carry) {
            refcntStorage =
                SIDE_TABLE_RC_PINNED | (oldRefcnt & SIDE_TABLE_FLAG_MASK);
            return true;
        }
        else {
            refcntStorage = newRefcnt;
            return false;
        }
    }
Copier le Code

Verrouillé pendant l'opération de hachage , Cela affecte le rendement ,Donc, dansextra_rc À plein régime , Met la moitié de son état complet dans la table de hachage , Évitez les hachages fréquents .En même tempsextra_rc L'état complet n'est pas fréquent non plus. slowpath(carry),Donc la moitié de l'état complet a déjà beaucoup d'espace de stockage!

2.releaseMéthodes

release Le processus de traitement est facile à comprendre , Inversion du nombre de références .TrouverreleaseSource d'implémentation pour:

image.png

La libération détermine également si l'objet courant est un petit objetTaggedPointer,Si c'est un petit objet, il n'est pas nécessaire de traiter le nombre de références. Appelé si ce n'est pas un petit objet releaseMéthodes. Continuer à suivre le Code ,Enfin appelé àrootReleaseMéthodes,Voir ci - dessous:

image.png

De même, il décidera toujours si nopointerisa、Est - ce que la libération,Si ce n'est pas le cas,,Oui.extra_rcMoins1Fonctionnement,Voir le code ci - dessous:

    uintptr_t carry;
    newisa.bits = subc(newisa.bits, RC_ONE, 0, &carry);  // extra_rc--

    if (slowpath(carry)) {
        // don't ClearExclusive()
        goto underflow;
    }
Copier le Code

Un bit d'étiquette est également défini carry,Pour jugerextra_rc A - t - il été vidé? ?Siextra_rc Le nombre de références pour 0, Et nous y arriverons. underflowEn cours.InunderflowMoyenne, Déterminer d'abord si l'objet a une table de hachage ,Si elle existe, Supprime certains comptes de référence du hachage extra_rcMoyenne,Voir le code ci - dessous:

    // Try to remove some retain counts from the side table.        
    auto borrow = sidetable_subExtraRC_nolock(RC_HALF);
    
    bool emptySideTable = borrow.remaining == 0; // we'll clear the side table if no refcounts remain there
    
    // Paramètresextra_rc, Et définissez le hachage , Effacer le hachage 
    newisa.extra_rc = borrow.borrowed - 1;  // redo the original decrement too
    newisa.has_sidetable_rc = !emptySideTable;
Copier le Code

Dans ce processus,Assigne une partie du nombre de références dans le hachage àextra_rcMoyenne,En même temps, Selon le nombre de références restantes , Pour définir si le hachage doit être vidé . Si le hachage est défini à emptySideTable,Vide,Est appelésidetable_clearExtraRC_nolock La méthode SideTableDeSideTables Effacement moyen :

if (emptySideTable)
                sidetable_clearExtraRC_nolock();

void
objc_object::sidetable_clearExtraRC_nolock()
{
    ASSERT(isa.nonpointer);
    SideTable& table = SideTables()[this];
    RefcountMap::iterator it = table.refcnts.find(this);
    table.refcnts.erase(it);
}
Copier le Code

Quandextra_rc La valeur est vide , La table de hachage est également effacée , Alors à ce moment - là isDeallocatingStatut,Va entrer.deallocateEn cours,EnvoyerdeallocMessage, Terminer la libération de l'objet .

    if (performDealloc) {
        ((void(*)(objc_object *, SEL))objc_msgSend)(this, @selector(dealloc));
    }
Copier le Code

3.dealloc

deallocEnfin, on appellerootDeallocMéthodes,Voir le code ci - dessous:

image.png

Lorsque l'objet est libéré ,Ce n'est pas difficile à comprendre., Déterminer d'abord s'il s'agit d'un petit objet , Les petits objets n'ont pas besoin d'être traités , Parce que le système nous libère automatiquement . Simultanément à travers l'objet isaDéterminer si oui ou nonnonpointer isa, Si vous continuez à juger s'il peut y avoir des références faibles 、 Existe - t - il un objet associé? 、 Existe - t - il un profilage? 、 Existe - t - il une table de hachage? . Si le contenu ci - dessus n'existe pas, il est appelé freeMéthodes, Libérer l'objet .Si elle existe,Appeléobject_disposeMéthodes.Voir le code ci - dessous:

image.png image.png

Si un objet associé existe ,Adoption_object_remove_assocations Méthodes pour libérer les objets associés . Cette partie du contenu est classée Extension et classification des classes (Catégorie) A analysé .Par appelclearDeallocatingMéthodes, Terminer la libération des tables de hachage et des tables de référence faibles , Cette section est disponible en weakPrincipes de mise en œuvre et processus de destruction Est également décrit dans .

image.png

4.retainCount

Le dernier appel pour obtenir le nombre de références est rootretainCountMéthodes, Voir la figure ci - dessous pour la mise en œuvre du code source :

image.png

Déterminer d'abord si oui ou non est un petit objet , Les petits objets ne sont pas comptés par référence .Si ouinonpointer isa,D'abord à partir deisa Obtenir à partir du pointeur extra_rcValeur numérique, Déterminer également s'il existe une table de hachage ,Si elle existe, Ajouter les valeurs dans le hachage .Si ce n'est pas le cas,nonpointer isa, Obtenir directement la correspondance objet SideTable Nombre de références dans .

版权声明
本文为[GufsMiroir]所创,转载请带上原文链接,感谢
https://cdmana.com/2021/09/20210914173525263h.html

Scroll to Top