对象的本质
objc_object结构体,⾥⾯存储isa指针和成员变量的值
class_getInstanceSize:实际占用的内存空间
malloc_size:系统开辟的内存空间
sizeof:变量的内存大小(类即指针大小,结构体即结构体大小)
OSTestObject1 *objc1 = [[OSTestObject1 alloc] init];
objc1->count=10;
(lldb) x/6gx objc1
0x6000006718a0: 0x0000000101fdc660 0x0000000000000000
0x6000006718b0: 0x0000000000000000 0x000000000000000a
0x6000006718c0: 0x0000000000000000 0x0000000000000000
0x000000000000000a 存count的值
对象⾥⾯存储了⼀个isa指针 + 成员变量的值,isa指针是固定的,占8个字节,所以影响对象内存的只有成员变量(属性会⾃动⽣成带下划线的成员变量)。在对象的内部是以8字节进⾏对⻬的。苹果会⾃动重成员变量的顺序,将占⽤不⾜ 8 字节的成员挨在⼀起,凑满 8 字节,以达到优化内存的⽬的。
isa指针探索
联合体和结构体
结构体(struct)中所有变量是“共存”的,⽽联合体(union)中是各变量是“互斥”的,只能存在⼀个。struct内存空间的分配是粗放的,不管⽤不⽤,全部分配。这样带来的⼀个坏处就是对于内存的消耗要⼤⼀些。但是结构体⾥⾯的数据是完整的。联合体⾥⾯的数据只能存在⼀个,但优点是内存使⽤更为精细灵活,也节省了内存空间。
位域
位域的宽度不能超过前⾯数据类型的最⼤⻓度,⽐如int占4个字节也就是32位,那后⾯的数字就不能超过32。⼀个位域存储在同⼀个字节中,如⼀个字节所剩空间不够存放另⼀位域时,则会从下⼀单元起存放该位域。位域能够节省⼀定的内存空间
[xxx alloc] 最后调用 _class_createInstanceFromZone,查看源码
初始化isa 指针 obj->initIsa(cls);
objc_object::initIsa(Class cls)
{
initIsa(cls,false,false);
}
是一个 Class 类型
typedef struct objc_class *Class;
struct objc_class : objc_object
Class是一个对象,因为继承objc_object
objc_object 存在 isa_t isa;
union isa_t {
isa_t() { }
isa_t(uintptr_tvalue) :bits(value) { }
uintptr_tbits;
...
public:
#if defined(ISA_BITFIELD)
struct{
ISA_BITFIELD; // defined in isa.h
};
...
#endif
}
ISA_BITFIELD分平台的
arm64 (真机) 位域
uintptr_t nonpointer : 1;
uintptr_t has_assoc : 1;
uintptr_t has_cxx_dtor : 1;
uintptr_t shiftcls : 33;
uintptr_t magic : 6;
uintptr_t weakly_referenced : 1;
uintptr_t unused : 1;
uintptr_t has_sidetable_rc : 1;
uintptr_t extra_rc : 19
isa_t联合体大小是8个字节
nonPointerIsa
nonPointerIsa是内存优化的⼀种⼿段。isa是⼀个Class类型的结构体指针,占8个字节,主要是⽤来存内存地址的。但是8个字节意味着它就有8*8=64位。存储地址根本不需要这么多的内存空间。⽽且每个对象都有个isa指针,这样就浪费了内存。所以苹果就把和对象⼀些息息相关的东⻄,存在了这块内存空间⾥⾯。这种isa指针就叫nonPointerIsa。