OC底层原理-alloc流程
alloc流程分析
可以通過opensource下載objc4來查看alloc的源碼,這里用objc4-818版本來分析
1.alloc
+ (id)alloc {return _objc_rootAlloc(self); }2.objc_alloc
id objc_alloc(Class cls) {return callAlloc(cls, true/*checkNil*/, false/*allocWithZone*/); }3.callAlloc
static ALWAYS_INLINE id callAlloc(Class cls, bool checkNil, bool allocWithZone=false) { #if __OBJC2__if (slowpath(checkNil && !cls)) return nil;if (fastpath(!cls->ISA()->hasCustomAWZ())) {return _objc_rootAllocWithZone(cls, nil);} #endif// No shortcuts available.if (allocWithZone) {return ((id(*)(id, SEL, struct _NSZone *))objc_msgSend)(cls, @selector(allocWithZone:), nil);}return ((id(*)(id, SEL))objc_msgSend)(cls, @selector(alloc)); }ISA方法:
inline Class objc_object::ISA(bool authenticated) {ASSERT(!isTaggedPointer());return isa.getDecodedClass(authenticated); }// class or superclass has default alloc/allocWithZone: implementation // Note this is is stored in the metaclass. #define FAST_CACHE_HAS_DEFAULT_AWZ (1<<14) bool hasCustomAWZ() const {return !cache.getBit(FAST_CACHE_HAS_DEFAULT_AWZ); }在callAlloc中,先通過cls的ISA返回一個Class對象,然后判斷cache中有沒有緩存,如果有,則執行_objc_rootAllocWithZone,如果沒有,則執行objc_msgSend。
4._objc_rootAllocWithZone
id _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused) {// allocWithZone under __OBJC2__ ignores the zone parameterreturn _class_createInstanceFromZone(cls, 0, nil,OBJECT_CONSTRUCT_CALL_BADALLOC); }5._class_createInstanceFromZone
static ALWAYS_INLINE id _class_createInstanceFromZone(Class cls, size_t extraBytes, void *zone,int construct_flags = OBJECT_CONSTRUCT_NONE,bool cxxConstruct = true,size_t *outAllocatedSize = nil) {ASSERT(cls->isRealized());// Read class's info bits all at once for performancebool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();bool hasCxxDtor = cls->hasCxxDtor();bool fast = cls->canAllocNonpointer();size_t size;size = cls->instanceSize(extraBytes);if (outAllocatedSize) *outAllocatedSize = size;id obj;if (zone) {obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);} else {obj = (id)calloc(1, size);}if (slowpath(!obj)) {if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {return _objc_callBadAllocHandler(cls);}return nil;}if (!zone && fast) {obj->initInstanceIsa(cls, hasCxxDtor);} else {// Use raw pointer isa on the assumption that they might be// doing something weird with the zone or RR.obj->initIsa(cls);}if (fastpath(!hasCxxCtor)) {return obj;}construct_flags |= OBJECT_CONSTRUCT_FREE_ONFAILURE;return object_cxxConstructFromClass(obj, cls, construct_flags); }_class_createInstanceFromZone創建實例分三步:
1.cls->instanceSize 計算對象所需要的的內存大小
2.cls->calloc 申請開辟內存
3.cls->initInstanceIsa 通過isa,將對象于類關聯
instanceSize
inline size_t instanceSize(size_t extraBytes) const {if (fastpath(cache.hasFastInstanceSize(extraBytes))) {return cache.fastInstanceSize(extraBytes);}size_t size = alignedInstanceSize() + extraBytes;// CF requires all objects be at least 16 bytes.if (size < 16) size = 16; return size;}size_t fastInstanceSize(size_t extra) const{ASSERT(hasFastInstanceSize(extra));if (__builtin_constant_p(extra) && extra == 0) {return _flags & FAST_CACHE_ALLOC_MASK16;} else {size_t size = _flags & FAST_CACHE_ALLOC_MASK;// remove the FAST_CACHE_ALLOC_DELTA16 that was added// by setFastInstanceSizereturn align16(size + extra - FAST_CACHE_ALLOC_DELTA16);}}uint32_t unalignedInstanceSize() const {ASSERT(isRealized());return data()->ro()->instanceSize;}// Class's ivar size rounded up to a pointer-size boundary.uint32_t alignedInstanceSize() const {return word_align(unalignedInstanceSize());}當cache中有緩存時,就調用fastInstanceSize來計算extraBytes,并返回大小,在fastInstanceSize中調用了align16進行16字節對齊;沒有緩存時,調用alignedInstanceSize進行8字節對齊。
calloc
calloc內部進行了16字節對齊,具體可以參考這里
initInstanceIsa
inline void objc_object::initInstanceIsa(Class cls, bool hasCxxDtor) {ASSERT(!cls->instancesRequireRawIsa());ASSERT(hasCxxDtor == cls->hasCxxDtor());initIsa(cls, true, hasCxxDtor); }inline void objc_object::initIsa(Class cls, bool nonpointer, UNUSED_WITHOUT_INDEXED_ISA_AND_DTOR_BIT bool hasCxxDtor) { ASSERT(!isTaggedPointer()); isa_t newisa(0);if (!nonpointer) {newisa.setClass(cls, this);} else {ASSERT(!DisableNonpointerIsa);ASSERT(!cls->instancesRequireRawIsa());#if SUPPORT_INDEXED_ISAASSERT(cls->classArrayIndex() > 0);newisa.bits = ISA_INDEX_MAGIC_VALUE;// isa.magic is part of ISA_MAGIC_VALUE// isa.nonpointer is part of ISA_MAGIC_VALUEnewisa.has_cxx_dtor = hasCxxDtor;newisa.indexcls = (uintptr_t)cls->classArrayIndex(); #elsenewisa.bits = ISA_MAGIC_VALUE;// isa.magic is part of ISA_MAGIC_VALUE// isa.nonpointer is part of ISA_MAGIC_VALUE # if ISA_HAS_CXX_DTOR_BITnewisa.has_cxx_dtor = hasCxxDtor; # endifnewisa.setClass(cls, this); #endifnewisa.extra_rc = 1;}// This write must be performed in a single store in some cases// (for example when realizing a class because other threads// may simultaneously try to use the class).// fixme use atomics here to guarantee single-store and to// guarantee memory order w.r.t. the class index table// ...but not too atomic because we don't want to hurt instantiationisa = newisa; }可見,在initIsa里面新生成了isa,并將其和cls關聯起來
總結
在alloc執行流程中,cache中沒有緩存,使用objc_msgSend函數調用了alloc方法,然后再調用 _objc_rootAlloc -> callAlloc -> _objc_rootAllocWithZone -> _class_createInstanceFromZone -> instanceSize -> calloc -> initInstanceIsa
如果有緩存,就不會通過objc_msgSend調用alloc方法,就直接 _objc_rootAllocWithZone執行后面的流程
其實,alloc的主要目的就是開辟內存,并使得isa指針和cls類進行關聯。
總結
以上是生活随笔為你收集整理的OC底层原理-alloc流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 花10年时间学程序就能做好吗?
- 下一篇: 在word中如何不改变小节标题的前提下对