We’ve already seen how objects are created, but there’s a small detail here. Obj = (id)calloc(1, size) is executed in the _class_createInstanceFromZone method. Obj ->initInstanceIsa(CLS, hasCxxDtor); Obj is the MYPerson object that we created, because we initialized an ISA and associated it with the class, and we know that we can find the class from the object’s ISA, so today we’re going to look at isa
One: What is ISA
Isas come in two types: a pure pointer (Class type) and a nonpointer (nonpointer) and some other information to optimize memory. We all know that an ISA is 8 bytes and 64 bits, so each of these bits contains some information about the class for memory optimization.
1. Definition of ISA
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
2. Definition of Class
Class is actually a pointer to objc_class
struct objc_class : objc_object {
// Class ISA;
Class superclass;
cache_t cache; // formerly cache pointer and vtable
class_data_bits_t bits; // class_rw_t * plus custom rr/alloc flags
class_rw_t *data() {
return bits.data();
}
.....此处省略
}
Copy the code
3. The bits are defined
typedef unsigned long uintptr_t;
Copy the code
From the above definition, isa is actually an ISA_T union with CLS and BITS members. What is the union? The union shares memory with its internal members, and the size of memory depends on which member occupies the most memory, either a structure pointer or an unsigned long, both of which are 8 bytes, so isa_t is 8 bytes.
Two: isa memory optimization
We start with the bit field ISA_BITFIELD in the ISA_T union
1. A domain
The following is the definition of bit-field in Baidu Encyclopedia
Information is generally accessed in bytes. In fact, sometimes it is not necessary to store one or more bytes of information; for example, “true” or “false” is represented by 0 or 1, but only one bit. When the computer is used in the field of process control, parameter detection or data communication, the control information usually only occupies one or several bits in a byte, and several bits of information are often put in a byte
2. ISA_BITFIELD
define
# 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 // ULL represents a hex suffix mask
# 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)
# else
# error unknown architecture for packed isa
# endif
Copy the code
As we can see from the code, there are two architectures, ARM64 and X86_64, but the bitfield size is 8 bytes, 64 bits.
3. What does each stand for
- Nonpointer: indicates whether pointer optimization is enabled for isa Pointers
- 0: pure ISA pointer
- 1: Not only class object address, ISA contains class information, object reference count, etc
- Has_assoc: flag bit of the associated object. 0 does not exist and 1 exists
- Has_cxx_dtor: does the object have a destructor for C++ or Objc? If it has a destructor, the destructor logic needs to be done. If not, the object can be freed faster
- Shiftcls: Stores the value of the class pointer. With pointer optimization turned on, 33 bits are used to store class Pointers in the ARM64 architecture.
- 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 an object is pointed to or has been pointed to an ARC weak variable. Objects without weak references can be released faster.
- Deallocating: Indicates whether the object is freeing memory
- ** has_SIDETABLE_rc :** When the object reference technique is greater than 10, this variable is borrowed to store carry
- Extra_rc: When representing the referential count value of this object, it is actually the referential count value minus 1
As you can see from the above, a lot of information is stored in the bitfield, and the 8-byte 64-bit bits have been used to their fullest extent. Note that Shiftcls stores the value of the class pointer, which is also used to find the class to which it belongs
Three: ISA points to analysis
Class inherits from NSObject, so there must be ISA, and ISA must come first
Class stuClass = [STU1 Class] First, look at the internal implementation of the class method. We see that the object_getClass(self) method is called
- (Class)class {
return object_getClass(self);
}
Copy the code
Object_getClass (self) internal implementation
Class object_getClass(id obj)
{
if (obj) return obj->getIsa();
else return Nil;
}
Copy the code
Internal implementation of getIsa
objc_object::getIsa()
{
if(! isTaggedPointer())return ISA();
uintptr_t ptr = (uintptr_t)this;
if (isExtTaggedPointer()) {
uintptr_t slot =
(ptr >> _OBJC_TAG_EXT_SLOT_SHIFT) & _OBJC_TAG_EXT_SLOT_MASK;
return objc_tag_ext_classes[slot];
} else {
uintptr_t slot =
(ptr >> _OBJC_TAG_SLOT_SHIFT) & _OBJC_TAG_SLOT_MASK;
returnobjc_tag_classes[slot]; }}Copy the code
The key point here is ISA(), which takes a look at its internal implementation
objc_object::ISA() { assert(! isTaggedPointer());#if SUPPORT_INDEXED_ISA
if (isa.nonpointer) {
uintptr_t slot = isa.indexcls;
return classForIndex((unsigned)slot);
}
return (Class)isa.bits;
#else
return (Class)(isa.bits & ISA_MASK);
#endif
}
Copy the code
Return (Class)(ISa.bits & ISA_MASK) returns the value of the bitwise and operation to Class. ISA_MASK is the mask, which has been defined in the above bit field –> 0x0000000ffffffff8ULL
Let’s verify our conjecture by printing the memory structure of stu1, so 0x001d8001000014a9 represents ISA
(lldb) x/4xg stu1
0x1018131d0: 0x001d8001000014a9 0x0000000000000000
0x1018131e0: 0x72726f43534e5b2d 0x65546e6f69746365
(lldb)
Copy the code
At this point we print 0x001D8001000014a9 and there’s nothing there, right
(lldb) po 0x001d8001000014a9
8303516107936937
Copy the code
Let’s try this (ISa.bits & ISA_MASK), plus the mask.
(lldb) p/x 0x001d8001000014a9 & 0x0000000ffffffff8
(long) $7 = 0x00000001000014a8
(lldb) po 0x00000001000014a8
WYStudent
Copy the code
At this point, our conjecture has been verified and we have obtained the information of the class through ISA.
In the same way as above, the class isa points to the metaclass, the metaclass ISA points to the root metaclass, and the root metaclass ISA points to itself.