1. Consortium and bitfield

1.1 structure

Let’s start with the following code:

struct SSLCar { BOOL front; BOOL back; BOOL left; BOOL right; }sslCar; NSLog (@ "sslCar: % lu", sizeof (sslCar)); SslCar: 4Copy the code

We see that an SSLCar structure is four bytes, that is, 32 bits (0000 0000 0000 0000 0000 0000 0000), whereas the four BOOL values in SSLCar require only four bits (1111) to be stored, resulting in a very large waste of space.

1.2 a domain

Specify 1 bit for each member variable by bitfield:

struct SSLCar2 { BOOL front: 1; BOOL back : 1; BOOL left : 1; BOOL right: 1; }sslCar2; NSLog (@ "sslCar2: % lu", sizeof (sslCar2)); Print result: SSLCAR2:1Copy the code

At this point, the memory space has been well optimized.

1.3 a consortium

Create a consortium:

union SSLPerson {
    char *name;
    int  age;
};
Copy the code

Assign the union and print:

By printing the result, we find that the union only has a value for the variable that was assigned after.

1.4 Difference between structure and union

All variables in a struct are “co-existing” — the advantage is “tolerant” and comprehensive; The disadvantage is that the allocation of struct memory space is extensive, regardless of use, full allocation.

In a union, the variables are mutually exclusive — the disadvantage is that they are not “inclusive” enough. But the advantage is that memory usage is more delicate and flexible, and also saves memory space.

2. Object nature

Add the following code to main.m:

@interface SSLPerson : NSObject

@property (nonatomic, copy) NSString *sslName;

@end

@implementation SSLPerson

@end


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        
    }
    return 0;
}
Copy the code

Compile main.m with the clang command (more clang info here) :

clang -rewrite-objc main.m -o main.cpp
Copy the code

We get the main. CPP file, and in main. CPP we can see information about the object:

typedef struct objc_class *Class; Struct objc_object {// 7661 line Class _Nonnull ISA __attribute__((deprecated)); }; typedef struct objc_object *id; // 7666 line typedef struct objc_object SSLPerson; // 111793 line struct SSLPerson_IMPL {// 111793 line struct NSObject_IMPL NSObject_IVARS; NSString *_sslName; };Copy the code

The object isa structure of type objc_object with an isa pointer of type Class.

Open the source code and check out objc_object:

struct objc_object { private: isa_t isa; . }Copy the code

3. Isa structure analysis

We in the OC object principle exploration (a), mentioned obj->initIsa(CLS), its role is to associate Pointers and classes, we use the source code for detailed analysis.

InitIsa function:

inline void objc_object::initIsa(Class cls) { initIsa(cls, false, false); } objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) { ASSERT(! isTaggedPointer()); isa_t newisa(0); // isa initializes if (! nonpointer) { newisa.setClass(cls, this); } else {ASSERT(! DisableNonpointerIsa); ASSERT(! cls->instancesRequireRawIsa()); #if SUPPORT_INDEXED_ISA ASSERT(cls->classArrayIndex() > 0); newisa.bits = ISA_INDEX_MAGIC_VALUE; newisa.has_cxx_dtor = hasCxxDtor; newisa.indexcls = (uintptr_t)cls->classArrayIndex(); #else newisa.bits = ISA_MAGIC_VALUE; # if ISA_HAS_CXX_DTOR_BIT newisa.has_cxx_dtor = hasCxxDtor; # endif newisa.setClass(cls, this); #endif newisa.extra_rc = 1; } isa = newisa; }Copy the code

Click to see isa_t;

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    Class cls;
    uintptr_t bits;
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
#endif
};
Copy the code

Click to see ISA_BITFIELD:

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
#   define ISA_MAGIC_MASK  0x000003f000000001ULL
#   define ISA_MAGIC_VALUE 0x000001a000000001ULL
#   define ISA_BITFIELD                                                      \
      uintptr_t nonpointer        : 1;                                       \
      uintptr_t has_assoc         : 1;                                       \
      uintptr_t has_cxx_dtor      : 1;                                       \
      uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ \
      uintptr_t magic             : 6;                                       \
      uintptr_t weakly_referenced : 1;                                       \
      uintptr_t deallocating      : 1;                                       \
      uintptr_t has_sidetable_rc  : 1;                                       \
      uintptr_t extra_rc          : 19
#   define RC_ONE   (1ULL<<45)
#   define RC_HALF  (1ULL<<18)

# elif __x86_64__
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_BITFIELD                                                        \
      uintptr_t nonpointer        : 1;                                         \
      uintptr_t has_assoc         : 1;                                         \
      uintptr_t has_cxx_dtor      : 1;                                         \
      uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ \
      uintptr_t magic             : 6;                                         \
      uintptr_t weakly_referenced : 1;                                         \
      uintptr_t deallocating      : 1;                                         \
      uintptr_t has_sidetable_rc  : 1;                                         \
      uintptr_t extra_rc          : 8
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)
Copy the code

Take a look at isa’s memory distribution:

  • nonpointer: indicates whether it is correctisaPointer Pointer optimization is enabled.0: pureisaA pointer,1: Not only class object address,isaContains class information, object reference counts, and so on.
  • has_assoc: Flag bit of the associated object,0No,1There is.
  • has_cxx_dtor: Indicates whether the object hasC++orObjcIf there is a destructor, it needs to do the destructor logic, if there is no, it can be faster to free the object.
  • shiftcls: Stores the value of the class pointer. Turn on pointer optimization in case ofarm64In the architecture33Bits are used to store class Pointers.
  • magic: used by the debugger to determine whether the current object is a real object or has no space to initialize.
  • weakly_referenced: indicates whether the object is or has been pointed to oneARCObjects without weak references can be freed faster.
  • deallocating: indicates whether the object is freeing memory.
  • extra_rc: represents the reference count value of the object. If there is not enough storage,has_sidetable_rcThe value of delta is going to be 1;
  • has_sidetable_rc: if for1, indicating that the reference count is too large to be stored inisaIn, the excess reference count is stored inSideTabletheRefCountMapIn the. So, ifisaisnonpointer, the object’s reference count is stored in itsisa_ttheextra_rcAnd in theSideTabletheRefCountMapIn the.

Conclusion:

  • isaDivided intononpointerThe types and thenonpointerType. nonnonpointerThe type is a pure pointer,nonpointerA type also contains information about reference counts, associated objects, and so on.
  • isausingA consortium+A domainTo store information. Because in theiOSEverything is object, object is used inisa, which can greatly save memory space.

4. Isa association class

Create an SSLperson class, initialize [SSLperson alloc], and debug in initIsa:

As shown in the figure above, a union newisa is created where the variables are currently 0 and no values are assigned.

Continue down:

As shown in the figure above, newISa.bits = ISA_MAGIC_VALUE, ISA_MAGIC_VALUE isa macro = 0x001D800000000001. The variables assigned are bits=8303511812964353, CLS = 0x001D800000000001, NonPointer =1, magic=59. Convert to binary representation:

  • 0x001d800000000001=8303511812964353, their binary representation is the same.
  • nonpointerThe binary representation of1.magicThe binary representation of111011, they are contained inbitsBinary representation of.

Breakpoint to enter setClass:

  • hereisaandSSLPersonClass is associated.
  • Is currently thenonpointer“, so it will not be givenclsThe assignment.
  • SSLPersonA class of address> > 3for10Base conversion, and then assign toshiftcls.
    • Why move to the rightthree?shiftclsinisaIs stored from the fourth bit, like thisisa & ISA_MASKIn order to get accurateClass address.

Continue down:

  • shiftcls.extra_rcIs also successfully assigned.
  • I’ve always had a question hereclsWhy is it assigned when it’s notSSLPerson, andA consortiumI should be able toclsSo I did a debugging in the later stage:
    • Print theclsPhi, it’s really the wholeisaThe value of, as for why displaySSLPersonI think the system did something.

At this point, the exploration of isa and class association is basically completed, and will continue to be updated if there isa deeper understanding in the future.