alloc是iOS中创建对象、开辟内存的方法,本文就学习下alloc在底层做了什么.
1. alloc
代码准备,开始调试。 调试方法:
- 断点调试
- 汇编:Debug->Debug Workflow->Always Show Disassembly
int main(int argc, const char * argv[]) {
@autoreleasepool {
// insert code here...
Person *person = [Person alloc];
}
return 0;
}
1.1 _objc_rootAlloc 和 _objc_rootAlloc
+ (id)alloc {
return _objc_rootAlloc(self);
}
id
_objc_rootAlloc(Class cls)
{
return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}
1.2 callAlloc
// Call [cls alloc] or [cls allocWithZone:nil], with appropriate
// shortcutting optimizations.
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
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 canAllocFasts 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;
}
}
}
if (fastpath(!cls->ISA()->hasCustomAWZ()))
:hasCustomAWZ
意为hasCustomAllocWithZone
,判断有没有allocWithZone
的实现(只有不是继承NSObjcet/NSProxy的类才为true)if (fastpath(cls->canAllocFast()))
:内部调用了bits.canAllocFast
默认为false。- 可以确定此处创建对象会走
class_createInstance
方法,
1.3 class_createInstance
id
class_createInstance(Class cls, size_t extraBytes)
{
return _class_createInstanceFromZone(cls, extraBytes, nil);
}
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 info bits all at once for performance
bool hasCxxCtor = cls->hasCxxCtor(); // 判断当前class或superclass是否有.cxx_construct 构造方法的实现
bool hasCxxDtor = cls->hasCxxDtor(); // 判断当前class或superclass是否有.cxx_destruct 析构方法的实现
bool fast = cls->canAllocNonpointer(); // 判断是否支持优化的isa
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); // 对象size计算
}
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;
}
instanceSize()
:获取对象的大小calloc()
:动态开辟内存,接下来的文章会学习initInstanceIsa()
:初始化isa,接下来的文章会学习
至此,已经完成了初始化isa并开辟内存空间,那我们来看看instanceSize
如何获取对象大小的。
1.4 字节对齐
#ifdef __LP64__
# define WORD_MASK 7UL
#else
# define WORD_MASK 3UL
#endif
static inline uint32_t word_align(uint32_t x) {
return (x + WORD_MASK) & ~WORD_MASK;
}
// May be unaligned depending on class ivars.
uint32_t unalignedInstanceSize() {
assert(isRealized());
return data()->ro->instanceSize;
}
// Class ivar size rounded up to a pointer-size boundary.
uint32_t alignedInstanceSize() {
return word_align(unalignedInstanceSize());
}
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;
}
size_t instanceSize
:获取对象的大小lignedInstanceSize()
:获取类所需要的内存大小unalignedInstanceSize()
->data()->ro->instanceSize
:获取这个类所有属性内存的大小。这里只有继承NSObject的一个属性isa,所以返回8字节word_align
:(x + WORD_MASK) & ~WORD_MASK
字节对齐算法,64位系统下,对象大小采用8字节对齐。if (size < 16) size = 16
:对象大小至少是16字节。
结论:
64位系统下,对象大小采用8字节对齐;
实际申请的内存最低为16字节。
1.5 alloc流程图
instanceSize
:计算对象大小。calloc
:申请开辟空间。initInstanceIsa
:指针关联对象。
2. init流程
// Replaced by CF (throws an NSException)
+ (id)init {
return (id)self;
}
- (id)init {
return _objc_rootInit(self);
}
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;
}
init底层没有做什么操作,直接返回了obj。
- 这样做是一种抽象工厂设计模式,让代码实现更加自由;
- 我们可以在子类中重写init方法,在重写的init方法中做一些初始化操作。
3. new源码
+ (id)new {
return [callAlloc(self, false/*checkNil*/) init];
}
- new = alloc + init。