SoFunction
Updated on 2025-03-04

iOS memory management reference counting example analysis

Memory management mechanism

The current popular memory management mechanisms are mainlyGCandRCTwo types.

  • GC(Garbage Collection): Garbage collection mechanism, regularly searches for objects that are no longer used, and frees up the memory occupied by objects.
  • RC(Reference Counting): Reference Counting mechanism. Use reference counts to manage the memory of an object. When you need to hold an object, make its reference count +1; when you do not need to hold an object, make its reference count -1; when an object's reference count is 0, the object will be destroyed.

Objective-CSupports three memory management mechanisms:ARCMRCandGC,butObjective-CofGCThe mechanism has platform limitations, onlyMacOSUnder development,iOSThe development usesRCMechanism fromMRCUntil nowARC

A newly created OC object reference count is 1 by default. When the reference count is reduced to 0, the OC object will be destroyed, freeing up the memory space it consumes.

CallretainWill make the reference count of the OC object +1, callreleaseWill make the reference count of the OC object-1

Summary of experience in memory management

  • When calledallocnewcopymutableCopyThe method returns an object, and when this object is not needed, it must be calledreleaseorautoreleaseLet it be released
  • If you want to have an object, let its reference count +1; if you don't want to have an object, let its reference count -1
  • You can use the following private functions to view the situation of automatically releasing the pool

extern void _objc_autoreleasePoolPrint(void);

As a result, we have made a preliminary understanding of the concept of "reference counting". The "object" in Objective-C manages its memory life cycle through the reference counting function. So, how are the reference counts of objects stored? In which data structure is it stored?

First of all, I have to mentionisa

isa

  • isaPointers are used to maintain the relationship between "object" and "class" and ensure that objects and classes can passisaPointer finds the corresponding methods, instance variables, attributes, protocols, etc.;
  • Before the arm64 architecture,isaIt's just an ordinary pointer that points directly toobjc_class, storedClassMeta-ClassThe memory address of the object.instanceThe object'sisaPoint toclassObject,classThe object'sisaPoint tometa-classobject;
  • Starting with the arm64 architecture,isaOptimized, usingnonpointerIt means that it becomes a common body (union) structure, and also uses bit fields to store more information. Separate 64-bit memory data to store a lot of things, 33 of which are used to storeclassmeta-classThe memory address information of the object. To pass the bit operationisaValue of& ISA_MASKOnly by getting the maskclassmeta-classThe memory address of the object.
// 
struct objc_object {
    Class isa;  // Before arm64 architecture};
// 
struct objc_object {
private:
    isa_t isa;  // Start with arm64 architecture};
union isa_t 
{
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }
    Class cls;
    uintptr_t bits;
#if SUPPORT_PACKED_ISA
    // extra_rc must be the MSB-most field (so it matches carry/overflow flags)
    // nonpointer must be the LSB (fixme or get rid of it)
    // shiftcls must occupy the same bits that a real class pointer would
    // bits + RC_ONE is equivalent to extra_rc + 1
    // RC_HALF is the high bit of extra_rc (. half of its range)
    // future expansion:
    // uintptr_t fast_rr : 1;     // no r/r overrides
    // uintptr_t lock : 2;        // lock for atomic property, @synch
    // uintptr_t extraBytes : 1;  // allocated with extra bytes
# if __arm64__ // Under the __arm64__ architecture# define ISA_MASK 0x000000ffffffff8ULL // Used to retrieve the memory address of Class and Meta-Class objects#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
    struct {
        uintptr_t nonpointer        : 1;  // 0: Represents an ordinary pointer, storing the memory addresses of Class and Meta-Class objects                                          // 1: It means that it has been optimized and uses bit domain to store more information        uintptr_t has_assoc         : 1;  // Is there any associated object set? If not, it will be faster when released        uintptr_t has_cxx_dtor      : 1;  // Is there a C++ destructor (.cxx_destruct)? If not, it will be faster when released        uintptr_t shiftcls          : 33; //Storing memory address information of Class and Meta-Class objects        uintptr_t magic             : 6;  // Used to determine whether the object has not completed initialization during debugging        uintptr_t weakly_referenced : 1;  // Is it a weak reference pointing to it? If not, it will be faster when it is released        uintptr_t deallocating      : 1;  // Is the object being released        uintptr_t has_sidetable_rc  : 1;  // If it is 1, it means that the reference count is too large and cannot be stored in isa. The exceeded reference count will be stored in a hash table called the SideTable structure        uintptr_t extra_rc          : 19; // The value stored in it is the number of reference counts outside the object itself, retainCount - 1#       define RC_ONE   (1ULL<<45)
#       define RC_HALF  (1ULL<<18)
    };
......  // Under the __x86_64__ architecture};

ifisaNononpointer, i.e. before the arm64 architectureisapointer. Since it's just a normal pointer, it's storedClassMeta-ClassThe memory address of the object, so it cannot store the reference count itself, so the reference count of the object was stored in aSideTableStructuralRefCountMap(Reference Count Table) hash table.

ifisayesnonpointer, then it itself can store some reference counts. From aboveunion isa_tWe can know from the definition ofisa_tThere are two reference count related things stored in it:extra_rcandhas_sidetable_rc

  • extra_rc: The value stored in it is the number of reference counts outside the object itself. If these 19 bits are not enough to be stored,has_sidetable_rcThe value of 1 will become 1;
  • has_sidetable_rc: If it is 1, it means that the reference count is too large and cannot be stored inisaIn, then the exceeded reference count will be storedSideTableofRefCountMapmiddle.

So, ifisayesnonpointer, then the reference count of the object is stored in itsisa_tofextra_rcChinese andSideTableofRefCountMapmiddle.

SideTable

// 
struct SideTable {
    spinlock_t slock;        // Spin lock    RefcountMap refcnts;     // Reference count table (hash table)    weak_table_t weak_table; // Weak reference table (hash list)    ......
}

SideTableStored inSideTables()middle,SideTables()It is essentially a hash table. You can use the object pointer to get which one it corresponds to (reference count table or weak reference table) is in.SideTablemiddle. In non-embedded systems,SideTables()64 out ofSideTable. The following isSideTables()Definition:

// 
static objc::ExplicitInit<StripedMap<SideTable>> SideTablesMap;
static StripedMap<SideTable>& SideTables() {
    return ();
}

Therefore, looking for the reference count table of an object requires two hash searches:

  • ① The first time is to search for the current object's memory address through hashingSideTables()Take out where it isSideTable
  • ② The second time, based on the memory address of the current object, search for theSideTableIn-houserefcntsTake out its reference count table.

Use multipleSideTable+Separated lock technical solution is to ensure thread safety while taking into account access efficiency

The above is the detailed content of the iOS memory management reference counting example analysis. For more information about iOS memory management reference counting, please pay attention to my other related articles!