iOS底层原理 :isa探索分析

这是我参与更文挑战的第5天,活动详情查看: [更文挑战]

前文回顾:

iOS底层原理 :OC对象的本质

OC:结构体(struct)/位域/联合体(union)

之前已经通过clang查看过对象在C++是什么样子的了,接下来结合源码分析下对象的本质。

isa探寻

首先在源码中查看objc_class的定义,并没有发现什么有用的价值。objc_class只是包含了一个Class isa,而Class只是objc_class的一个指针别名,好一个套娃。

typedef struct objc_class *Class;

struct objc_class {
    Class _Nonnull isa  OBJC_ISA_AVAILABILITY;

#if !__OBJC2__
    Class _Nullable super_class                              OBJC2_UNAVAILABLE;
    const char * _Nonnull name                               OBJC2_UNAVAILABLE;
    long version                                             OBJC2_UNAVAILABLE;
    long info                                                OBJC2_UNAVAILABLE;
    long instance_size                                       OBJC2_UNAVAILABLE;
    struct objc_ivar_list * _Nullable ivars                  OBJC2_UNAVAILABLE;
    struct objc_method_list * _Nullable * _Nullable methodLists                    OBJC2_UNAVAILABLE;
    struct objc_cache * _Nonnull cache                       OBJC2_UNAVAILABLE;
    struct objc_protocol_list * _Nullable protocols          OBJC2_UNAVAILABLE;
#endif

} OBJC2_UNAVAILABLE;
复制代码

接下来只能回顾到源码对象alloc中,因为在过程中出现过initInstanceIsa,只能顺着这个查看了。顺利找到关键步骤objc_object::initIsaisa_t应该就是我们的isa了。

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;
        // 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
#   if ISA_HAS_CXX_DTOR_BIT
        newisa.has_cxx_dtor = hasCxxDtor;
#   endif
        newisa.setClass(cls, this);
#endif
        newisa.extra_rc = 1;
    }

    // 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;
}
复制代码

isa_t是这样的。

union isa_t {
    isa_t() { }
    isa_t(uintptr_t value) : bits(value) { }

    uintptr_t bits;

private:
    // Accessing the class requires custom ptrauth operations, so
    // force clients to go through setClass/getClass by making this
    // private.
    Class cls;

public:
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };

    bool isDeallocating() {
        return extra_rc == 0 && has_sidetable_rc == 0;
    }
    void setDeallocating() {
        extra_rc = 0;
        has_sidetable_rc = 0;
    }
#endif
复制代码

然后在宏定义ISA_BITFIELD终于找到了我们isa里面是存的啥了。

image.png

isa分析

nonpointer

nonpointer表示对指针时候开启优化 0:纯isa指针,1:不止包含对象地址,还包含类信息、对象引用计数、弱引用等。

has_assoc

has_assoc 是否有设置过关联对象,如果没有,释放时会更快

has_cxx_dtor

has_cxx_dtor 是否有C++的析构函数(.cxx_destruct),如果没有,释放时会更快

shiftcls

shiftcls 存储着Class、Meta-Class对象的内存地址信息,在nonpointer=1的情况下,在arm64架构中有33位用来存储类指针 (重点)

magic

magic 用于在调试时分辨对象是否未完成初始化

weakly_referenced

weakly_referenced 是否有被弱引用指向过,如果没有,释放时会更快。弱引用表。

deallocating

deallocating 对象是否正在释放

has_sidetable_rc

has_sidetable_rc 引用计数器是否过大无法存储在isa中
如果为1,那么引用计数会存储在一个叫SideTable的类的属性中

extra_rc

extra_rc 里面存储的值是引用计数器减1,如果引用计数10这里面存的9,如果引用计数大于10则需要使用has_sidetable_rc

isa测试

既然已经发现了isa的内存储,接下来就要测试下isa了。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享