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