首先展示一张oc对象alloc的流程图:
分析alloc的流程需要借助oc源码,oc源码可以去官网下载,也可以在逻辑cooci大神的GitHub地址下载,官网下载的源码需要自己配置才能编译成功,配置过程有点繁琐,cooci大神GitHub地址的源码是已经编译成功的,有需要的友友们可以自行选择下载。
接下来从这句
OCPeople *ocp = [[OCPeople alloc] init];
断点进入探索流程,
1. 断点进入alloc,会发现内部调用了另外一个函数,代码如下:
+ (id)alloc {
return _objc_rootAlloc(self);
}
复制代码
2. 断点进入_objc_rootAlloc,会发现这个函数向下层传递了两个参数checkNil和allocWithZone,代码如下:
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
复制代码
3. 断点进入callAlloc,这个函数里面出现了两个宏slowpath和fastpath,slowpath表示传入条件后结果为假的可能性很大,所以不会走if,也不会返回nil,fastpath表示传入条件后结果为真的可能性很大。__OBJC2__是判断是否为objc2.0版本,兼容objc1.0的逻辑,现在用的都是新版本objc2.0,所以会走这段if,代码如下:
// Call [cls alloc] or [cls allocWithZone:nil], with appropriate
// shortcutting optimizations.
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
if (slowpath(checkNil && !cls)) return nil;
#if __OBJC2__
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
// No alloc/allocWithZone implementation. Go straight to the allocator.
// fixme store hasCustomAWZ in the non-meta class and
// add it to canAllocFast's summary
if (fastpath(cls->canAllocFast())) {
// No ctors, raw isa, etc. Go straight to the metal.
bool dtor = cls->hasCxxDtor();
id obj = (id)calloc(1, cls->bits.fastInstanceSize());
if (slowpath(!obj)) return callBadAllocHandler(cls);
obj->initInstanceIsa(cls, dtor);
return obj;
}
else {
// Has ctor or raw isa or something. Use the slower path.
id obj = class_createInstance(cls, 0);
if (slowpath(!obj)) return callBadAllocHandler(cls);
return obj;
}
}
#endif
// No shortcuts available.
if (allocWithZone) return [cls allocWithZone:nil];
return [cls alloc];
}
复制代码
3.1 根据上面的代码,fastpath(cls->canAllocFast())为真时,断点obj->initInstanceIsa(cls, dtor);
进入initInstanceIsa看下,代码如下:
inline void
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
assert(!cls->instancesRequireRawIsa());
assert(hasCxxDtor == cls->hasCxxDtor());
initIsa(cls, true, hasCxxDtor);
}
复制代码
3.2 根据上面的代码,fastpath(cls->canAllocFast())为假时,断点id obj = class_createInstance(cls, 0);
进入class_createInstance看下,里面调用了_class_createInstanceFromZone函数,代码如下:
id
class_createInstance(Class cls, size_t extraBytes)
{
return _class_createInstanceFromZone(cls, extraBytes, nil);
}
复制代码
4. 断点进入_class_createInstanceFromZone,这段代码就是alloc的核心,创建实例。size_t size = cls->instanceSize(extraBytes);
是计算需要开辟的内存空间大小,传入的extraBytes为0;obj = (id)calloc(1, size);
是向系统申请开辟内存空间;obj->initInstanceIsa(cls, hasCxxDtor);
是将类cls和是否有c++析构器传入给initInstanceIsa,实例化isa,关联到相应的类,代码如下:
static __attribute__((always_inline))
id
_class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,
bool cxxConstruct = true,
size_t *outAllocatedSize = nil)
{
if (!cls) return nil;
assert(cls->isRealized());
// Read class's info bits all at once for performance
bool hasCxxCtor = cls->hasCxxCtor();
bool hasCxxDtor = cls->hasCxxDtor();
bool fast = cls->canAllocNonpointer();
size_t size = cls->instanceSize(extraBytes);
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (!zone && fast) {
obj = (id)calloc(1, size);
if (!obj) return nil;
obj->initInstanceIsa(cls, hasCxxDtor);
}
else {
if (zone) {
obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
} else {
obj = (id)calloc(1, size);
}
if (!obj) return nil;
// Use raw pointer isa on the assumption that they might be
// doing something weird with the zone or RR.
obj->initIsa(cls);
}
if (cxxConstruct && hasCxxCtor) {
obj = _objc_constructOrFree(obj, cls);
}
return obj;
}
复制代码
5. 断点进入size_t size = cls->instanceSize(extraBytes);
看下instanceSize函数的实现,这段代码就是计算需要的内存空间大小,如果占用的内存空间<16,则返回16,代码如下:
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
if (size < 16) size = 16;
return size;
}
复制代码
6. 断点进入alignedInstanceSize,内部调用了另外一个函数,代码如下:
// Class's ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
复制代码
7. word_align是字节对齐,参数unalignedInstanceSize是uint32_t类型,断点进入word_align,~WORD_MASK
是WORD_MASK值取反的意思,(x + WORD_MASK) & ~WORD_MASK
这一整句的意思是(x + WORD_MASK)的值和WORD_MASK取反的值进行与运算,x传入的是8,WORD_MASK现在是7,就是(8+7)&~7=00001111&~00000111=00001000,最后等于8,这个过程就是8字节对齐算法,取8的整数倍。这一句也等同于(x + WORD_MASK)>>3<<3
,(x + WORD_MASK)右移3位再左移3位。word_align代码如下:
static inline uint32_t word_align(uint32_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
复制代码
以上就是alloc的探索过程中的部分代码,流程图会显示的详细些。alloc的核心就是开辟内存,通过isa指针关联到相应的类。
以上探索流程参考了cooci大神和学员的博客,感谢老师和同学们的分享!
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END