窺探
通過(guò)下符號(hào)斷點(diǎn)的方式來(lái)跟蹤 [NSObject alloc]
//下了兩個(gè)符號(hào)斷點(diǎn)
1翩隧、objc_alloc
2友驮、+[NSObject alloc]
//結(jié)果是 1 2
經(jīng)過(guò)編譯器一頓操作,似乎結(jié)合和預(yù)想不是完全吻合
在使用+[NSObject alloc]
的時(shí)候?qū)嶋H上調(diào)用的是libonjc.A.dylib objc_alloc
异旧,并不是預(yù)想的libonjc.A.dylib objc_msgSend
,這里看一llvm
的源碼,對(duì)alloc
做了處理(第一次調(diào)用objc_alloc
,第二次調(diào)用+alloc
)
梳理
1. 從objc_alloc開(kāi)始
// Calls [cls alloc].
id
objc_alloc(Class cls)
{
return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/);
}
- 這里就做一件事情設(shè)置兩個(gè)參數(shù)
checkNil = true
、allocWithZone = false
- 初次調(diào)用
callAlloc
需要檢查nil
,而且不使用zone
2. callAlloc
static id callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
if (slowpath(checkNil && !cls)) return nil;
#if __OBJC2__
//是否實(shí)現(xiàn) allocWithZone
if (fastpath(!cls->ISA()->hasCustomAWZ())) {
//未實(shí)現(xiàn)allocWithZone
// canAllocFast直接返回了false右遭,直接看else
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 {
// 核心 創(chuàng)建實(shí)例
id obj = class_createInstance(cls, 0);
if (slowpath(!obj)) return callBadAllocHandler(cls);
return obj;
}
}
#endif
// No shortcuts available.
if (allocWithZone) return [cls allocWithZone:nil];
//+alloc 終于輪到你了
return [cls alloc];
}
-
hasCustomAWZ()
是檢查是否實(shí)現(xiàn)了+allocWithZone
- 沒(méi)有實(shí)現(xiàn)
+allocWithZone
就通過(guò)class_createInstance(cls, 0)
來(lái)創(chuàng)建實(shí)例 - 實(shí)現(xiàn)了
+allocWithZone
,但還需要allocWithZone == true
才會(huì)調(diào)用,首次調(diào)用一定不會(huì)觸發(fā)在objc_alloc
中傳了false
-
return [cls alloc];
最后這段代碼才是主流程
3. class_createInstance
class_createInstance(Class cls, size_t extraBytes)
{
//調(diào)用了 私有方法 _class_createInstanceFromZone
return _class_createInstanceFromZone(cls, extraBytes, nil);
}
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(); //有c++構(gòu)造函數(shù)
bool hasCxxDtor = cls->hasCxxDtor(); //有c++析構(gòu)函數(shù)
bool fast = cls->canAllocNonpointer(); //快速創(chuàng)建窘哈,是否允許非純指針吹榴,也就是isa的優(yōu)化
//計(jì)算實(shí)例大小
size_t size = cls->instanceSize(extraBytes);
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
if (!zone && fast) {
//不使用zone并且支持isa優(yōu)化的對(duì)象分配空間
obj = (id)calloc(1, size);
if (!obj) return nil;
//對(duì)象實(shí)例初始化isa
obj->initInstanceIsa(cls, hasCxxDtor);
}
else {
if (zone) {
//使用zone 分配空間
obj = (id)malloc_zone_calloc ((malloc_zone_t *)zone, 1, size);
} else {
//不使用 zone分配空間
obj = (id)calloc(1, size);
}
if (!obj) return nil;
//純指針的初始化
obj->initIsa(cls);
}
if (cxxConstruct && hasCxxCtor) {
obj = _objc_constructOrFree(obj, cls);
}
return obj;
}
3. instanceSize
//拿到類(lèi)對(duì)象的 ro 對(duì)象的原始大小
uint32_t unalignedInstanceSize() {
assert(isRealized());
return data()->ro->instanceSize;
}
/*
字節(jié)對(duì)齊: 為了讓CPU 尋址更簡(jiǎn)單快速,用空間換時(shí)間
*/
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
//計(jì)算對(duì)象大小
size_t instanceSize(size_t extraBytes) {
size_t size = alignedInstanceSize() + extraBytes;
// CF requires all objects be at least 16 bytes.
//最小 16個(gè)字節(jié)
if (size < 16) size = 16;
return size;
}
關(guān)于字節(jié)對(duì)齊的內(nèi)容
4. InitIsa
inline void
objc_object::initIsa(Class cls)
{
//純指針的初始化 isa 方法
initIsa(cls, false, false);
}
inline void
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
//非純指針的初始化 isa 方法
initIsa(cls, true, hasCxxDtor);
}
/*
初始化Isa
參數(shù):
cls 類(lèi)對(duì)象
nonpointer 是否是非指針滚婉,就是經(jīng)過(guò)優(yōu)化的isa
hasCxxDtor 是否存在c++析構(gòu)
*/
inline void
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
{
assert(!isTaggedPointer());
//
if (!nonpointer) {
isa.cls = cls;
} else {
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;
isa = newisa;
}
}
5. +alloc
+ (id)alloc {
return _objc_rootAlloc(self);
}
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
- 未實(shí)現(xiàn)
+allocWithZone
將會(huì)調(diào)用+ alloc
图筹,然后再次調(diào)用callAlloc
,這次參數(shù)不一樣了不需要檢查是否為空让腹,使用zone
總結(jié)
- 控制調(diào)用
callAlloc
參數(shù)來(lái)控制執(zhí)行路徑远剩,從而實(shí)現(xiàn)不同情況下創(chuàng)建對(duì)象 - 對(duì)純指針和非純指針的初始化
- 內(nèi)存直接對(duì)齊
附上alloc分析圖
alloc.jpg