开发中,我们经常使用到[[xxx alloc] init],但却没有真正理解过alloc,init,现在进行深入了解一下。
alloc,init的功能
1.先看看这样的一个例子
//创建一个Person类,然后引用对应头文件
Person *p1 = [Person alloc];
Person *p2 = [p1 init];
Person *p3 = [p1 init];
NSLog(@"%p-%p", p1, &p1);
NSLog(@"%p-%p", p2, &p2);
NSLog(@"%p-%p", p3, &p3);
运行结果如图:
运行结果
- p1,p2,p3的指向地址都相同
- p1,p2,p3的地址不同
2.alloc与init的关系如图

- alloc生成对象地址。
- init分配指针地址,并指向对象地址
alloc流程
需要看到alloc流程,可到苹果开源网站下载。
如果要将源码进行编译调试,可参见
对源码进行分析
从alloc方法一步一步点进去我们分别能看到:
//NSObject.mm文件中 +alloc方法
+ (id)alloc {
return _objc_rootAlloc(self);
}
//NSObject.mm文件中 _objc_rootAlloc(Class cls)方法
id _objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
//NSObject.mm文件中 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));
}
//objc-runtime-new.mm文件中 _objc_rootAllocWithZone(Class cls, malloc_zone_t *zone __unused)方法
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文件中 _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 performance
bool 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);
}
1. 前几步一条路进入可以不提,在callAlloc方法中,出现了分支slowpath和fastpath,快速路径与慢速路径,可以理解为大多数情况走快速路径,极少情况走慢速路径,这样写便于运行效率的提升,所以我们继续研究_objc_rootAllocWithZone方法。
2. 紧接着我们到了关键的_class_createInstanceFromZone方法:
- _class_createInstanceFromZone第一个研究的方法
size = cls->instanceSize(extraBytes);
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 setFastInstanceSize
return align16(size + extra - FAST_CACHE_ALLOC_DELTA16);
}
}
经过调试,我们能看到进入fastInstanceSize方法,然后执行return align16(size + extra - FAST_CACHE_ALLOC_DELTA16);
static inline size_t align16(size_t x) {
return (x + size_t(15)) & ~size_t(15);
}
很明显,这是在进行内存对齐(下一章节具体讲解)
3. 得到一个16字节倍数大小size,然后执行obj = (id)calloc(1, size);分配内存空间(ps:if (zone)现已废弃,不做过深研究)
当我们在执行obj = (id)calloc(1, size);后我们答应obj可以看到:

而我们一个对象的打印的格式应该为
<Person: 0x10060de90>,所以calloc只是分配了一个地址空间,并没有创建新的指针指向它。也证明了前面alloc的说法
4.当我们执行完obj->initInstanceIsa(cls, hasCxxDtor);我们拿到我们想要的结果:

综上alloc运行流程如图:
