美文网首页
003-OC对象原理探究 - isa 和 nonpointer

003-OC对象原理探究 - isa 和 nonpointer

作者: Mr_wick | 来源:发表于2021-06-17 19:41 被阅读0次

引言

001-OC对象原理探究 - alloc这篇文章的探索过程中,大体上讲述了alloc的基本流程。其中探索到_class_createInstanceFromZone方法中的下面这段代码时,简单讲了对象的关联。

if (!zone && fast) {
        obj->initInstanceIsa(cls, hasCxxDtor);
    } else {
        obj->initIsa(cls);
    }

因此,本文将详细探究这个神秘的isa

initInstanceIsainitIsa源码

我们在源码中,点击initInstanceIsa(cls,hasCxxDtor)进入到objc-object.h中可以看到,函数内部做了两个断言

ASSERT(!cls->instancesRequireRawIsa());
ASSERT(hasCxxDtor == cls->hasCxxDtor());

1、instancesRequireRawIsa()内部为cache.getBit(FAST_CACHE_REQUIRES_RAW_ISA);。其中FAST_CACHE_REQUIRES_RAW_ISA为类的cache_t中的uint16_t _flags第13位是否为1,以此来表示类对象(非实例对象)是否需要原始的isa。

2、cls->hasCxxDtor()内部为cache.getBit(FAST_CACHE_HAS_CXX_DTOR);。其中FAST_CACHE_HAS_CXX_DTOR为类cache_tuint16_t _flags第2位是否为1,以此来表示当前类或者父类是否有c++的析构函数的实现。

接下来就是进入到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_ISA
        ASSERT(cls->classArrayIndex() > 0);
        newisa.bits = ISA_INDEX_MAGIC_VALUE;
        newisa.has_cxx_dtor = hasCxxDtor;
        newisa.indexcls = (uintptr_t)cls->classArrayIndex();
#else
        newisa.bits = ISA_MAGIC_VALUE;
#   if ISA_HAS_CXX_DTOR_BIT
        newisa.has_cxx_dtor = hasCxxDtor;
#   endif
        newisa.setClass(cls, this);
#endif
        newisa.extra_rc = 1;
    }
    isa = newisa;
}

1、由initInstanceIsa调用的initIsanonpointer传的值为true,走的是else内部逻辑,对newisa多项赋值。
2、由obj->initIsa(cls);调用的initIsanonpointer传的值为false,走的是if内部逻辑,只对newisa的class设置即可。
3、在initIsa方法中,首先第一句就断言ASSERT(!isTaggedPointer());是否为TaggedPointer,如果是TaggedPointer则无法继续后续的逻辑,即无isa

isa的内部结构以及nonpointerTaggedPointer的解释

isa结构源码如下,是一个联合体+位域的结构:
联合体union内部成员为互斥存在,即联合体所占内存大小决定于内部最大成员所占大小。结构体struct则是“有容乃大”,占内存大小可参考002-OC对象原理探究 - 结构体内存对齐

union isa_t {
    isa_t() { } // 构造方法
    isa_t(uintptr_t value) : bits(value) { } // 构造方法
    uintptr_t bits;
private:
    Class cls;

public:
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // 此宏为isa内部位域的分配情况,源码在下面
    };
    bool isDeallocating() {
        return extra_rc == 0 && has_sidetable_rc == 0;
    }
    void setDeallocating() {
        extra_rc = 0;
        has_sidetable_rc = 0;
    }
#endif
    void setClass(Class cls, objc_object *obj);
    Class getClass(bool authenticated);
    Class getDecodedClass(bool authenticated);
};

其中ISA_BITFIELD此宏为isa内部位域的分配情况:(:1:44等分别表示该成员占1位44位

# if __arm64__                                                                                                    
        uintptr_t nonpointer        : 1;                                       
        uintptr_t has_assoc         : 1;                                       
        uintptr_t has_cxx_dtor      : 1;                                       
        uintptr_t shiftcls          : 33; /*MACH_VM_MAX_ADDRESS 0x1000000000*/ 
        uintptr_t magic             : 6;                                       
        uintptr_t weakly_referenced : 1;                                       
        uintptr_t unused            : 1;                                       
        uintptr_t has_sidetable_rc  : 1;                                       
        uintptr_t extra_rc          : 19
# elif __x86_64__                      
        uintptr_t nonpointer        : 1;                                         
        uintptr_t has_assoc         : 1;                                         
        uintptr_t has_cxx_dtor      : 1;                                         
        uintptr_t shiftcls          : 44; /*MACH_VM_MAX_ADDRESS 0x7fffffe00000*/ 
        uintptr_t magic             : 6;                                         
        uintptr_t weakly_referenced : 1;                                         
        uintptr_t unused            : 1;                                         
        uintptr_t has_sidetable_rc  : 1;                                         
        uintptr_t extra_rc          : 8

-nonpointer: 是否开启NONPOINTER isa指针优化;
-has_assoc: 对象是否含有关联引用
-has_cxx_dtor:对象是否含有 C++ 或者 Objc 的析构器
-shiftcls: 类的指针(重点)(arm64:33位,x86_64:44位)
-magic: 对象是否初始化完成 (arm64:0x16 ,x86_64:0x3b)
-weakly_referenced:是否为弱引用的对象
-deallocating:对象是否正在执行析构函数(是否在释放内存)
-has_sidetable_rc:判断是否需要用sidetable去处理引用计数,(extra_rc的大小影响到这个变量)
-extra_rc: 存储该对象的引用计数值减一后的结果
isa的二进制分布如图所示:

isa64情况.jpeg

TaggedPointer

早期64位架构中,存储基础数据类型 , 底层会封装成 NSNumber , 在开辟8字节内存,32位架构开辟4字节。维护引用计数,管理生命期 。造成运行效率上的损失 。会造成很大空间浪费。因此,引入TaggedPointer。当断言为TaggedPointer,则对象指针的值不是地址了,而是真正的值,直接优化了内存,提升了获取速度。TaggedPointer的更多知识,可阅读这篇文章

nonpointer

ISA_BITFIELD内部,可看到nonpointer占1位,表示是否对 isa 指针开启指针优化(0:纯isa指针,1:不⽌是类对象地址,isa 中包含了类信息、对象的引⽤计数等)。应用判断,在上面已说明。

isa的用法

isa的用法和isa的走向将在下篇文章探究。

总结

每个类都有一个isa,isa的探究重要性不言而喻。我们通过alloc流程探究到isa的内部结构,补上了001文章的alloc流程的一个坑。好累,拜拜。。

相关文章

网友评论

      本文标题:003-OC对象原理探究 - isa 和 nonpointer

      本文链接:https://www.haomeiwen.com/subject/wdmcyltx.html