objc4源码基于779.1版本。文章纯属个人学习见解,谬误之处,望指正。
alloc
方法调用栈
-
- (id)alloc
- _objc_rootAlloc()
- callAlloc()
- _objc_rootAllocWithZone()
- _class_createInstanceFromZone()
- cls->instanceSize()
- malloc_zone_calloc | calloc
- obj->initInstanceIsa()
- obj->initIsa()
- object_cxxConstructFromClass()
- _class_createInstanceFromZone()
- _objc_rootAllocWithZone()
- callAlloc()
- _objc_rootAlloc()
- (id)alloc
源代码详注
NSObject.mm
- line:2317
+ (id)alloc {
return _objc_rootAlloc(self);
}
复制代码
NSObject.mm
- line:1718
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
复制代码
NSObject.mm
- line:1697
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
// Objective-C 2.0
#if __OBJC2__
// 判空
if (slowpath(checkNil && !cls)) return nil;
// 本类或超类是否实现alloc/allocWithZone,没有则默认调用元类
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));
}
复制代码
objc-runtime-new.mm
- line:7440
NEVER_INLINE
id
_objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused)
{
// allocWithZone under __OBJC2__ ignores the zone parameter
return _class_createInstanceFromZone(cls, 0, nil,
OBJECT_CONSTRUCT_CALL_BADALLOC);
}
复制代码
objc-runtime-new.mm
- line:7386
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 performance
// 是否有C++构造器
bool hasCxxCtor = cxxConstruct && cls->hasCxxCtor();
// 是否有C++析构器
bool hasCxxDtor = cls->hasCxxDtor();
// 是否可分配优化指针
bool fast = cls->canAllocNonpointer();
size_t size;
// 初始化大小计算
size = cls->instanceSize(extraBytes);
if (outAllocatedSize) *outAllocatedSize = size;
id obj;
// 分配内存空间
if (zone) {
// 根据给定的 zone 和 size 分配内存
obj = (id)malloc_zone_calloc((malloc_zone_t *)zone, 1, size);
} else {
// 分配为0的内存
obj = (id)calloc(1, size);
}
// 分配失败
if (slowpath(!obj)) {
if (construct_flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
// 处理程序内部分配失败
return _objc_callBadAllocHandler(cls);
}
return nil;
}
// 初始化isa_t
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;
// 从子类到超类的递归地调用对象C++构造方法
return object_cxxConstructFromClass(obj, cls, construct_flags);
}
复制代码
objc-runtime-new.h
- line:1497
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.
// 最小16字节
if (size < 16) size = 16;
return size;
}
复制代码
objc-object.h
- line:215
inline void
objc_object::initInstanceIsa(Class cls, bool hasCxxDtor)
{
ASSERT(!cls->instancesRequireRawIsa());
ASSERT(hasCxxDtor == cls->hasCxxDtor());
// 初始化isa指针
initIsa(cls, true, hasCxxDtor);
}
复制代码
objc-object.h
- line:224
inline void
objc_object::initIsa(Class cls, bool nonpointer, bool hasCxxDtor)
{
ASSERT(!isTaggedPointer());
// nonpointer false:普通指针 true:优化指针
if (!nonpointer) {
// 初始化普通指针
isa = isa_t((uintptr_t)cls);
} else {
ASSERT(!DisableNonpointerIsa);
ASSERT(!cls->instancesRequireRawIsa());
// 初始化优化指针
isa_t newisa(0);
#if SUPPORT_INDEXED_ISA
// 支持类表索引
ASSERT(cls->classArrayIndex() > 0);
newisa.bits = ISA_INDEX_MAGIC_VALUE;
// isa.magic is part of ISA_MAGIC_VALUE
// isa.nonpointer is part of ISA_MAGIC_VALUE
newisa.has_cxx_dtor = hasCxxDtor;
newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
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;
#endif
// 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 instantiation
isa = newisa;
}
}
复制代码
objc-class.mm
- line:487
id
object_cxxConstructFromClass(id obj, Class cls, int flags)
{
ASSERT(cls->hasCxxCtor()); // required for performance, not correctness
id (*ctor)(id);
Class supercls;
supercls = cls->superclass;
// Call superclasses' ctors first, if any.
// 父类是否有C++构造方法
if (supercls && supercls->hasCxxCtor()) {
// 递归调用父类构造方法
bool ok = object_cxxConstructFromClass(obj, supercls, flags);
// 失败返回 nil
if (slowpath(!ok)) return nil; // some superclass's ctor failed - give up
}
// Find this class's ctor, if any.
// 调用当前类的SEL_cxx_construct方法
ctor = (id(*)(id))lookupMethodInClassAndLoadCache(cls, SEL_cxx_construct);
// 构造方法为转发方法,则返回
if (ctor == (id(*)(id))_objc_msgForward_impcache) return obj; // no ctor - ok
// Call this class's ctor.
if (PrintCxxCtors) {
_objc_inform("CXX: calling C++ constructors for class %s",
cls->nameForLogging());
}
// 调用C++构造方法且成功则返回对象
if (fastpath((*ctor)(obj))) return obj; // ctor called and succeeded - ok
supercls = cls->superclass; // this reload avoids a spill on the stack
// This class's ctor was called and failed.
// Call superclasses's dtors to clean up.
// 调用失败处理
if (supercls) object_cxxDestructFromClass(obj, supercls);
if (flags & OBJECT_CONSTRUCT_FREE_ONFAILURE) free(obj);
if (flags & OBJECT_CONSTRUCT_CALL_BADALLOC) {
return _objc_callBadAllocHandler(cls);
}
return nil;
}
复制代码
init
NSObject.mm
line:2331
- (id)init {
return _objc_rootInit(self);
}
复制代码
NSObject.mm
line:1830
id
_objc_rootInit(id obj)
{
// In practice, it will be hard to rely on this function.
// Many classes do not properly chain -init calls.
// 没有其他操作行为,就返回参数对象
return obj;
}
复制代码
new
NSObject.mm
line:2245
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
复制代码
new方式和alloc+init方式在本质上并没有什么不同
源代码会常见到两个宏定义
#define fastpath(x) (__builtin_expect(bool(x), 1))
#define slowpath(x) (__builtin_expect(bool(x), 0))
复制代码
__builtin_expect(EXP,N)
是gcc提供的指令。意思是说fastpath中x的值大概率为真,slowpath中x的值大概率为假。
通过此指令优化编译器在编译时的代码布局,减少指令跳转带来的性能消耗。
malloc与calloc区别
两者都是动态分配内存。主要的不同是malloc不初始化分配的内存,已分配的内存中可以是任意的值。calloc 初始化已分配的内存为0。