iOS疑问之对象的isa初探索,对象的本质到底是什么?

118 阅读3分钟

在探索对象alloc的时候。遇到一个很关键信息 isa,另外对象的本质到底是什么,经过对alloc从底层源码探索后,也应该有一个比较清晰的框架了。 iOS开发用的是clang编译器,我们可以通过将.m文件clang编译为.cpp文件(C++)文件。因此看到一些隐藏在后面的内容。 命令行cd到需要转换文件的文件夹,clang -rewrite-objc main.m -o main.cpp运行即可,还可以使用xcode自带的xcrun,运行xcrun -sdk iphonesimulator clang -rewrite-objc main.m

image.png

先初始化一个类,然后生成cpp文件

image.png

得到一个cpp文件。定位到Goodgame。可以看待一个结构体。然后找到objc_object 的实现

image.png

image.png

objc_object就是isa,结构体

image.png

int main函数中,objc_getClass应该会和类有关系

image.png

objc_class探索到这里, -> objc_object->objc_class,而objc_class是在objc的源码中出现。

image.png

objc_class继承objc_object,组成

  • // Class ISA; 这里注释了isa,像是在提醒我们isa是继承来。
  • Class superclass; 指向的父类(类)
  • cache_t cache; 缓存相关,是个结构体,16字节
  • class_data_bits_t bits; 存放数据的地方,bits中有data
  • class_rw_t *data() const{...} 等等一大推条件

cache_t的组成

image.png

cache_t中源码比较多涉及到了方法查找流程,缓存策略,动态扩容,后期再补。

class_rw_t的实现

image.png

  • const class_ro_t *ro() 包含方法列表、ivars、属性、协议列表
  • const method_array_t methods() 方法列表
  • const property_array_t properties() 属性列表
  • const protocol_array_t protocols() 协议列表

objc_object

image.png

image.png ISA_BITFIELD

image.png 这段宏定义 可以看到,isa是一个联合体,有arm64 架构有x86_64架构

  • arm64架构下
#     define ISA_MASK        0x0000000ffffffff8ULL
#     define ISA_MAGIC_MASK  0x000003f000000001ULL
#     define ISA_MAGIC_VALUE 0x000001a000000001ULL
#     define ISA_HAS_CXX_DTOR_BIT 1
#     define ISA_BITFIELD                                                  
        uintptr_t nonpointer        : 1;  //0普通指针,1经过优化的指针,使用位域存更多信息                               
        uintptr_t has_assoc         : 1; //是否关联引用                                 
        uintptr_t has_cxx_dtor      : 1;// 是否C++析构函数或者dealloc。有的话释放更快                                   
        uintptr_t shiftcls          : 33;//存放Class、Meta—Class对象的内存地址  /*MACH_VM_MAX_ADDRESS 0x1000000000*/ 
        uintptr_t magic             : 6;//用于调式时对象是否完成初始化                                   
        uintptr_t weakly_referenced : 1;//是否内弱引用指向                                  
        uintptr_t unused            : 1;// 是否正在释放                                   
        uintptr_t has_sidetable_rc  : 1; //释放需要使用sidetable来存储引用计数                                  
        uintptr_t extra_rc          : 19; //引用计数能够用19个二进制存储
#     define RC_ONE   (1ULL<<45)
#     define RC_HALF  (1ULL<<18)
  • x86_64
#   define ISA_MASK        0x00007ffffffffff8ULL
#   define ISA_MAGIC_MASK  0x001f800000000001ULL
#   define ISA_MAGIC_VALUE 0x001d800000000001ULL
#   define ISA_HAS_CXX_DTOR_BIT 1
#   define ISA_BITFIELD                                                    
      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
#   define RC_ONE   (1ULL<<56)
#   define RC_HALF  (1ULL<<7)

简单做个对比shiftcls``extra_rc两个值不同。

  • has_sidetable_rc

image.png sidetables中包含N个sidetable。每个sidetable,包含spinlock_t slock;自旋锁.RefcountMap refcnts;引用计数.weak_table_t weak_table;弱引用表。为了数据安全而设计的。sidetable 单线程进行,效率低。多张表的sidetable,加上各自的自旋锁,速度快了,效率也高。 挖个坑 如何操作引用计数,从而牵引出内存管理、ARC