First, the commonwealth bit domain

Let’s define a structure

struct AppleCar1 {
    BOOL front;
    BOOL back;
    BOOL left;
    BOOL right;
};
Copy the code

Print size

struct AppleCar1 car1;
NSLog(@"car1 == %zd",sizeof(car1));
Copy the code

The results of

001- Consortium bitfield [6268:355746] car1 == 4
Copy the code

As you can see above, if you store four directions in a structure, you need four bytes. Next, we store them in bit-fields

struct AppleCar2 {
    BOOL front  :1;
    BOOL back   :1;
    BOOL left   :1;
    BOOL right  :1;
};
Copy the code

Let’s run print

struct AppleCar1 car1;
struct AppleCar2 car2;
NSLog(@"car1 ==%zd car2 ==%zd",sizeof(car1),sizeof(car2));
Copy the code

The results of

001- Consortium bitfield [6333:361078] car1 ==4 car2 ==1
Copy the code

So bitfields are more space efficient and let’s look at a structure

struct ApplePerson {
    char    *name;
    int     age;
    double  height;
};
Copy the code

Add a breakpoint

Print one step down

(lldb) p person1
(ApplePerson1) $0 = (name = 0x0000000000000000, age = 0, height = 0)
(lldb) p person1
(ApplePerson1) $1 = (name = "Library" x, age = 0, height = 0)
(lldb) p person1
(ApplePerson1) $2 = (name = "Library" x, age = 18, height = 0)
(lldb) 
Copy the code

All member variables in a structure can be assigned values

union ApplePerson2 {
    char    *name;
    int     age;
    double  height;
};
Copy the code

The breakpoint

Continue with the same steps above, printing one step down

(lldb) p person2
(ApplePerson2) $0 = (name = 0x0000000000000000, age = 0, height = 0)
(lldb) p person2 // The age and height member variables are dirty
(ApplePerson2) $1 = (name = "Library" x, age = 15936, height = 2.1220036643954044 e-314)
(lldb) p person2// Run again, age successfully assigned, name is empty, height is dirty
(ApplePerson2) $2 = (name = "", age = 18, height = 2.1219957998584539 e-314)
(lldb) 
Copy the code

Conclusion: Although the member variables of a community are the same as those of a structure, the member variables of a structure are co-existing, but the member variables of a community are mutually exclusive. Struct is all allocated, no use, and union is only allocated one, saving memory.

Isa analysis

In the previous article, initIsa was used to bind classes when allocating memory space for them

if(! zone && fast) { obj->initInstanceIsa(cls, hasCxxDtor); }else {
        // Use raw pointer isa on the assumption that they might be
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
}
Copy the code

Point initIsa in

inline void 
objc_object: :initIsa(Class cls)
{
    initIsa(cls, false.false);
}
Copy the code

Before going into initIsa

inline void 
objc_object: :initIsa(Class cls, bool nonpointer, bool hasCxxDtor) 
{ 
    if(! nonpointer) { isa = isa_t((uintptr_t)cls); }else {
      isa_t newisa(0);
#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;
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.shiftcls = (uintptr_t)cls >> 3; #endif isa = newisa; }}Copy the code

Isa = ISA_t ((uintptr_t) CLS); Point in

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

Find isa_t isa Commons and click back

if(! nonpointer) { isa = isa_t((uintptr_t)cls); }else{... }Copy the code

Reference:

itpcb.com/a/176630

Nonpointer_isa is not a pointer to a class. It also contains information about the class. A pointer to a class is 8 bytes long, but Pointers to a class object don’t need 8 bytes by 8 bits of address space. Key information such as reference counts, weak references, associated objects, destructors, etc… And then go back to isa_t

#include "isa.h"

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 on ISA_BITFIELD in struct, which posts the ARM64 bit architecture in ISA source code, to see the bit fields

# 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)
Copy the code

Reference:

www.jianshu.com/p/643847183…

Parameter names usage A domain size location
nonpointer Indicates whether to pointer to pure ISA

0: indicates the pure ISA pointer

1: non-pure ISA pointer, which stores more than the address of the class object. Isa contains information about the class and reference count of the object
1 0
has_assoc associations

Zero: no

1: there are
1 1
has_cxx_dtor Does the object have a destructor for C++ or Objc? If it has a destructor, then the destructor logic needs to be done. If not, the object can be freed faster 1 2
shiftcls Store the value of a class pointer. The X86_64 architecture uses 44-bit C storage, and the ARM64 architecture uses 33-bit storage for class Pointers. 33 3 ~ 35
magic Used by the debugger to determine whether the current object is a real object or has no space to initialize 6 36 ~ 41
weakly_referenced Objects without weak references can be released faster if they are or have been referred to an ARC weak variable. 1 42
deallocating Check whether memory is being freed 1 43
has_sidetable_rc Whether to use the plug-in reference count, when the object reference technique is greater than 10 need to borrow this variable to store carry 1 44
extra_rc Representation reference count 19 45 ~ 63

From above, the most important data is shiftcls, the pointer address of the class. Next we get the ISA address by printing the address of the object

Copy the code

A print

(lldb) x/4gx p
0x106017d20: 0x01000001000082e1 0x0000000000000000
0x106017d30: 0x0000000000000000 0x0000000000000000
(lldb) 
Copy the code

You can see that the ISA address is 0x01000001000082E1 and print the address of the class again

(lldb) p/x ApplePerson.class
(Class) $17 = 0x00000001000082e0 ApplePerson
Copy the code

Here we are going to get the class address 0x00000001000082E0 from the nonPOinter_ISA address 0x01000001000082E1, using the ISA mask

# if __arm64__
#   define ISA_MASK        0x0000000ffffffff8ULL
Copy the code

Put the ISA address and isa mask & below

(lldb) p/x 0x01000001000082e1 & 0x0000000ffffffff8ULL
(unsigned long long) $1 = 0x00000001000082e0
Copy the code

The address of the class is 0x00000001000082e0 and p/x applePerson. class is the same as the address of p/x applePerson. class

(lldb) x/4gx p
0x106017d20: 0x01000001000082e1 0x0000000000000000
0x106017d30: 0x0000000000000000 0x0000000000000000
(lldb)  
Copy the code

Now look at 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)
Copy the code

Shiftcls has 3 bits in the front and 28 bits in the back. We can get 33 bits in the middle by shifting it. First we move 3 bits to the right, then 31 bits to the left, and finally we move 28 bits to the right and return to the original position to get the pointer address of 33 bits

(lldb) x/4gx p
0x1005ba390: 0x01000001000082e1 0x0000000000000000
0x1005ba3a0: 0x75636f44534e5b2d 0x69766552746e656d
(lldb) p/x 0x01000001000082e1 >> 3
(long) $12 = 0x002000002000105c
(lldb) p/x 0x002000002000105c << 31
(long) $13 = 0x1000082e00000000
(lldb) p/x 0x1000082e00000000 >> 28
(long) $14 = 0x00000001000082e0
Copy the code

By pointer translation, we know that the address of Shiftcls is 0x00000001000082e0 and Po 0x00000001000082e0 to get the class

(lldb) po 0x00000001000082e0
ApplePerson
Copy the code

So let’s verify that again

(lldb) p/x ApplePerson.class
(Class) $15 = 0x00000001000082e0 ApplePerson
Copy the code

The same address is 0x00000001000082e0, exactly the same