Objective-C runtime机制(8)——OC对象从创建到销毁

在我们前面的几章中,分析了OC的runtime一些底层的数据结构以及实现机制。今天,我们就从一个OC对象的生命周期的角度,来解析在runtime底层是如何实现的。

我们创建一个对象(或对象引用)有几种方式?

Student *student = [[Student alloc] init];
Student *student2 = [Student new];

__weak Student *weakStudent = [Student new];

NSDictionary *dict = [[NSDictionary alloc] init];
NSDictionary *autoreleaseDict = [NSDictionary dictionary];

有很多种方式,我们就来依次看一下这些方式的背后实现。

alloc

要创建一个对象,第一步就是需要为对象分配内存。在创建内存时,我们会调用alloc方法。查看runtime的NSObject +alloc方法实现:

+ (id)alloc {
    return _objc_rootAlloc(self);
}
// Base class implementation of +alloc. cls is not nil.
// Calls [cls allocWithZone:nil].
id
_objc_rootAlloc(Class cls)
{
    return callAlloc(cls, false/*checkNil*/, true/*allocWithZone*/);
}

alloc方法会将self作为参数传入_objc_rootAlloc(Class cls) 方法中注意,因为alloc是一个类方法,因此此时的self是一个Class类型

最终该方法会落脚到callAlloc方法。

static ALWAYS_INLINE id callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
static ALWAYS_INLINE id
callAlloc(Class cls, bool checkNil, bool allocWithZone=false)
{
    if (slowpath(checkNil && !cls)) return nil;

#if __OBJC2__
    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 canAllocFast's summary
        if (fastpath(cls->canAllocFast())) { // 如果可以fast alloc,走这里
            // No ctors, raw isa, etc. Go straight to the metal.
            bool dtor = cls->hasCxxDtor();
            id obj = (id)calloc(1, cls->bits.fastInstanceSize()); // 直接调用 calloc方法,申请1块大小为bits.fastInstanceSize()的内存
            if (slowpath(!obj)) return callBadAllocHandler(cls);
            obj->initInstanceIsa(cls, dtor);
            return obj;
        }
        else { // 如果不可以fast alloc,走这里,
            // Has ctor or raw isa or something. Use the slower path.
            id obj = class_createInstance(cls, 0); // (1)需要读取cls 的class_ro_t 中的instanceSize,并使之大于16 byte, Because : CF requires all objects be at least 16 bytes. (2)initInstanceIsa
            if (slowpath(!obj)) return callBadAllocHandler(cls);
            return obj;
        }
    }
#endif

    // No shortcuts available.
    if (allocWithZone) return [cls allocWithZone:nil];
    return [cls alloc];
}

在callAlloc方法里面,做了三件事:

  1. 调用calloc方法,为类实例分配内存
  2. 调用obj->initInstanceIsa(cls, dtor)方法,初始化obj的isa
  3. 返回obj

在第一件事中,调用calloc方法,你需要提供需要申请内存的大小。在OC中有两条分支:
(1)can alloc fast
(2)can’t alloc fast

对于可以alloc fast的类,应该是经过编译器优化的类。这种类的实例大小直接被放到了bits

struct class_data_bits_t {

    // Values are the FAST_ flags above.
    uintptr_t bits;
	...
}

而不需要通过bits找到class_rw_t->class_ro_t->instanceSize。省略了这一条查找路径,而是直接读取位值,其创建实例的速度自然比不能alloc fast的类要快。

而对于不能alloc fast的类,则会进入第二条路径,代码会通过上面所说的通过bits找到class_rw_t->class_ro_t->instanceSize来确定需要申请内存的大小。

当申请了对象的内存后,还需要初始化类实例对象的isa成员变量:

 obj->initInstanceIsa(cls, hasCxxDtor);
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, bool hasCxxDtor) 
{ 
    assert(!isTaggedPointer()); 
    
    if (!nonpointer) { // 如果没有启用isa 优化,则直接将cls赋值给isa.cls,来表明当前object 是哪个类的实例
        isa.cls = cls;
    } else { // 如果启用了isa 优化,则初始化isa的三个内容(1) isa基本的内容,包括nonpointer置1以及设置OC magic vaule (2)置位has_cxx_dtor (3) 记录对象所属类的信息。 通过 newisa.shiftcls = (uintptr_t)cls >> 3;
        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;
    }
}

结合代码注释,以及我们在Objective-C runtime机制(5)——iOS 内存管理中提到的关于isa的描述,应该可以理解isa初始化的逻辑。

init

我们再来看一下init方法:

- (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;
}

实现很简单,就是将自身返回,没有做任何其他操作。

__strong

Student *student = [[Student alloc] init];
Student *student2 = [Student new];

在等号的左边,我们通过allocnew的方式创建了两个OC对象。而在右面,我们通过Student *的方式来引用这些对象。

在OC中,对对象所有的引用都是有所有权修饰符的,所有权修饰符会告诉编译器,该如何处理对象的引用关系。如果代码中没有显示指明所有权修饰符,则默认为__strong所有权。

因此上面代码实际是:

__strong Student *student = [[Student alloc] init];
__strong Student *student2 = [Student new];

对于new方法,苹果的文档解释为:

Allocates a new instance of the receiving class, sends it an initmessage, and returns the initialized object.

其实就是alloc + init 方法的简写。因此,这里的两种创建实例对象的方式可以理解是一个。

那么,当所有权修饰符是__strong时,runtime是如何管理对象引用的呢?

runtime会通过 void objc_storeStrong(id *location, id obj) 方法来处理__strong 引用。 这里的location就是引用指针,即Student *student,而obj就是被引用的对象,即Student实例

void objc_storeStrong(id *location, id obj)
{
    id prev = *location;
    if (obj == prev) {
        return;
    }
    objc_retain(obj); 	    //1.  retain obj
    *location = obj;		    //2.  将location 指向 obj
    objc_release(prev);   //3. release location之前指向的obj
}

代码逻辑很简单,主要是调用了objc_retain和objc_release两个方法。
我们分别来看一下它们的实现。

objc_retain

id 
objc_retain(id obj)
{
    if (!obj) return obj;
    if (obj->isTaggedPointer()) return obj;
    return obj->retain();
}

inline id 
objc_object::retain()
{
    assert(!isTaggedPointer());

    if (fastpath(!ISA()->hasCustomRR())) {
        return rootRetain();
    }

    return ((id(*)(objc_object *, 
  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值