OC的类本质是一个结构体
通过对main.m转换main.cpp可以看出,类对象的本质就是一个结构体。
@interface YSObject : NSObject
@property (nonatomic, assign) NSUInteger age;
@end
struct NSObject_IMPL {
Class isa;
};
struct YSObject_IMPL {
struct NSObject_IMPL NSObject_IVARS;
NSUInteger _age;
};
- 对象创建本质:
YSObject *p = [[YSObject alloc] init];
YSObject *p = ((YSObject *(*)(id, SEL))(void *)objc_msgSend)((id)((YSObject *(*)(id, SEL))(void *)objc_msgSend)((id)objc_getClass("YSObject"), sel_registerName("alloc")), sel_registerName("init"));
去掉类型转换得到:
YSObject *p = objc_msgSend(objc_msgSend(objc_getClass("YSObject"), sel_registerName("alloc")), sel_registerName("init"));
可以看出创建的过程只是向YSObject类
发送了sel_registerName("alloc")
和sel_registerName("init")
消息,无法分析内存分配的过程。那么发送这两条消息后发生了什么呢?通过查看汇编代码(Debug->Debug workflow->Always Show Disassembly
)发现调用了objc_alloc_init
方法
在Apple源码obj4中找到了
objc_alloc_init函数.pngobjc_alloc_init
函数(在NSObject.mm
文件中)
objc_alloc_init
函数中调用了callAlloc
函数
callAlloc函数.png
callAlloc
中调用了_objc_rootAllocWithZone
函数,全局搜索找到了它
_objc_rootAllocWithZone函数.png
在_objc_rootAllocWithZone
中调用了_class_createInstanceFromZone
和_class_createInstance
_class_createInstanceFromZone和_class_createInstance.png
从_class_createInstanceFromZone
中可以看出CF requires all objects be at least 16 bytes.
CF要求所有的对象至少有16字节。通过calloc
计算需要的内存大小
malloc_zone_calloc.png
把计算的bytes传给objc_constructInstance
返回创建的实例对象
objc_constructInstance
- 在' bytes '所指向的位置创建一个' cls '的实例。
- ' bytes '必须指向至少
class_getInstanceSize(cls)
的字节- 用0填充对齐内存。
- 设置新对象的isa。调用任何c++构造函数。
- 如果成功返回' bytes '。如果' cls '或' bytes '为空则返回nil
- nil,或者如果c++构造函数失败。 objc_constructInstance.png
至此,可以得出一个结论class_getInstanceSize(cls)
得到的是创建cls需要的最小内存,而是实际上,64位 iOS系统分配的是16的整数倍的空间,例如:class_getInstanceSize(cls)的值为24,那么最终分配的空间大小为16*2=32。
- malloc_size(const void *ptr)计算的是系统实际分配的内存
- sizeof()是计算数据类型的大小,在编译的时候就已经得出了结果
- 每一种数据类型都有自己的内存对齐方式
需要的最小内存为4+4+8 = 16(int占4个字节,isa指针占8个字节),实际class_getInstanceSize([YSObject class])计算的结果也是16。再加入一个char类型数据@interface YSObject : NSObject { int height; int age; } @end
需要的最小内存为4+4+1+8 = 17(char占1个字节),实际class_getInstanceSize([YSObject class])计算的结果却是24。简单来说就是在YSObject的实例对象创建的过程中做了内存对齐,而且class_getInstanceSize()的结果一定是8的倍数@interface YSObject : NSObject { char _name; int height; int age; } @end
size_t class_getInstanceSize(Class cls) { if (!cls) return 0; return cls->alignedInstanceSize(); } // Class's ivar size rounded up to a pointer-size boundary. // 类的成员变量大小四舍五入到一个指针大小的边界值 uint32_t alignedInstanceSize() const { return word_align(unalignedInstanceSize()); } // May be unaligned depending on class's ivars. // 根据类的成员变量不同,可能是未对齐的 uint32_t unalignedInstanceSize() const { ASSERT(isRealized()); return data()->ro()->instanceSize; } #ifdef __LP64__ # define WORD_SHIFT 3UL # define WORD_MASK 7UL # define WORD_BITS 64 #else # define WORD_SHIFT 2UL # define WORD_MASK 3UL # define WORD_BITS 32 #endif // 7UL表示 7unsigned long static inline uint32_t word_align(uint32_t x) { return (x + WORD_MASK) & ~WORD_MASK; }
calloc.png
calloc
函数的实现在libmalloc源码中
calloc
中调用的_malloc_zonecalloc
也是在libmalloc源码中
_malloc_zonecalloc.png
- 最终找到
kdebug_trace
但是在libmalloc源码中没有找到源码(放在以后再说)
MALLOC_TRACE.png
网友评论