The alloc process was analyzed in the last article, where the initialization of ISA was not explored. This article will continue to explore the initialization and pointing analysis of ISA.
Environment: Xcode 11.5
Source: objc4-781
In alloc, the calloc method allocates a certain amount of memory to store objects. What objects do we store?
static ALWAYS_INLINE id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone, int construct_flags = OBJECT_CONSTRUCT_NONE, bool cxxConstruct = true, size_t *outAllocatedSize = nil) { ... // Print obj and return 0x0000000101134ff0 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); } // print obj and return <ZHYObject: 0x101134ff0>...Copy the code
As you can see from the above print, it is only after initInstanceIsa that the system associates a particular memory space with a familiar class. We also know that an instance’s ISA points to its class, and a class’s ISA points to its metaclass. So how is it implemented inside ISA? What does the structure look like? First take a look at the internal implementation of initInstanceIsa.
inline void objc_object::initInstanceIsa(Class cls, bool hasCxxDtor) { assert(! cls->instancesRequireRawIsa()); assert(hasCxxDtor == cls->hasCxxDtor()); initIsa(cls, true, hasCxxDtor); } inline void objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor) { ... isa_t newisa(0); . newisa.bits = ISA_MAGIC_VALUE; // isa.magic is part of ISA_MAGIC_VALUE // isa.nonpointer is part of ISA_MAGIC_VALUE newisa.has_cxx_dtor = hasCxxDtor; newisa.shiftcls = (uintptr_t)cls >> 3; // This write must be performed in a single store in some cases // (for example when realizing a class because other threads // may simultaneously try to use the class). // fixme use atomics here to guarantee single-store and to // guarantee memory order w.r.t. the class index table // ... but not too atomic because we don't want to hurt instantiation isa = newisa; }}Copy the code
The initIsa method is eventually executed. By reading the source code, we can see that ISA_T is the core part that we need to explore.
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
Isa_t isa union type that also defines a bitfield, ISA_BITFIELD. You can read structs, unions, and bit-fields for unions, structures, and bit-fields. View the internal structure of this bitfield:
Only look at the definition under x86 # elif __x86_64__ # define ISA_MASK 0x00007ffffffffff8ULL / / binary representation is: 0 b0000000000000000011111111111111111111111111111111111111111111000 # define ISA_MAGIC_MASK 0 x001f800000000001ull / / binary representation is: 0 b0000000000011111100000000000000000000000000000000000000000000001 # define ISA_MAGIC_VALUE 0 x001d800000000001ull / / binary representation is: 0 b0000000000011101100000000000000000000000000000000000000000000001 # define ISA_BITFIELD uintptr_t nonpointer : 1; // uintptr_t has_assoc: 1; // uintptr_t has_cxx_dtor: 1; Uintptr_t shiftcls: 44; // Uintptr_t shiftcls: 44; // Uintptr_t shiftcls: 44; /*MACH_VM_MAX_ADDRESS 0x7ffffFE00000 Uintptr_t Weakly_referenced: 1; uintptr_t weakly_referenced: 1; // If the object is pointing to or used to point to an ARC weak variable, an object without a weak reference can release the uintptr_t deallocating: 1 faster; // Flag whether the object is releasing memory uintptr_t has_sidetable_rc: 1; // If the object reference technique is greater than 10, the variable needs to be borrowed to store the extra_rc in uintptr_t: 8; //axisPointer ... #endifCopy the code
You can see that the size of isa_t is 8 bytes, or 64 bits. Going back to the initIsa method above, the main code for ISA initialization is as follows:
isa_t newisa(0); // Initialize a union of isa_t newISa.bits = ISA_MAGIC_VALUE; newisa.has_cxx_dtor = hasCxxDtor; newisa.shiftcls = (uintptr_t)cls >> 3; // Store the corresponding class informationCopy the code
Next we verify with LLDB that the classes in ISA are stored in the same location as we found by reading the source code.
ZHYObject *object1 = [[ZHYObject alloc]init];
Copy the code
It was finally removed by a series of displacement operationsisa_t
4-47. withZHYObject
Class memory comparison found exactly the same.
In addition to that, in the previousisa_t
There is also a bit-field definition calledISA_MASK
The macro function is as a mask that we can pass directly withISA_MASK
To conduct a&
Operation, directly to the corresponding values, andZHYObject
The memory of the classes is the same.
Do not know everybody has this question, why representcls
Pointer toisa_t
The first in the union4
Bit start store? That means going through the maskISA_MASK
To get theshiftcls
The last three will always be0
This is because the memory we open up is based on8
Byte alignment, which means the memory address can only be8
The multiples of, that is, the last three are000
.
And then there’s this famous picture
This diagram represents instances of classes in ios, class objects, and a relationship between metaclasses and their superclasses. And oursZHYObject
For example, let’s verify.
X /4gx prints out the memory structure
struct objc_class : objc_object { // Class ISA; Class superclass; .Copy the code
In the figure above, we started from oneZHYObject
The instance starts throughisa
Look up step by step, in orderThe instance
->class
->The metaclass
->A metaclass
, found through memory comparison:
The instance
theisa
Points to theZHYObject metaclass
ZHYObject metaclass
theisa
Points to theA metaclass
A metaclass
theisa
Points to theA metaclass
Also, since the second 8 bytes in the obCJ_class structure represent its parent class, we can also verify that the reference to the parent class is correct, namely:
ZHYObject class
The parent classNSObject
ZHYObject metaclass
The parent classA metaclass
A metaclass
The parent classNSObject
NSObject
The parent classnil
That’s the initialization and pointing analysis of ISA.