类结构,objc_class

struct cache_t {

private:

    explicit_atomic _bucketsAndMaybeMask; //8

    union {

        struct {

            explicit_atomic    _maybeMask;  //4

#if __LP64__

            uint16_t                  _flags;  //2

#endif

            uint16_t                  _occupied;//2

        };

        explicit_atomic _originalPreoptCache; //8

    };



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;



struct objc_object {

private:

    isa_t isa;



struct objc_class : objc_object {

  objc_class(const objc_class&) = delete;

  objc_class(objc_class&&) = delete;

  void operator=(const objc_class&) = delete;

  void operator=(objc_class&&) = delete;

    // Class ISA;

    Class superclass;

    cache_t cache;            // formerly cache pointer and vtable

    class_data_bits_t bits;    // class_rw_t * plus custom rr/alloc flags

class_rw_t *data() const {

        return bits.data();

    }


  #define FAST_DATA_MASK          0x00007ffffffffff8UL


    class_rw_t* data() const {

        return (class_rw_t *)(bits & FAST_DATA_MASK);

    }


    struct class_rw_t {

    // Be warned that Symbolication knows the layout of this structure.

    uint32_t flags;

    uint16_t witness;

#if SUPPORT_INDEXED_ISA

    uint16_t index;

#endif

    explicit_atomic ro_or_rw_ext;

    Class firstSubclass;

    Class nextSiblingClass;

(lldb) x/4gx LGPerson.class

0x100008278: 0x00000001000082a0 0x0000000100801140

0x100008288: 0x0000000100ad4880 0x0002802c00000003

(lldb) p/x 0x100008278+0x20

(long) $1 = 0x0000000100008298

(lldb) p (class_data_bits_t *)0x0000000100008298

(class_data_bits_t *) $2 = 0x0000000100008298

(lldb) p $2->data()

(class_rw_t *) $3 = 0x0000000100ad4610

(lldb) p *$3

(class_rw_t) $4 = {

  flags = 2148007936

  witness = 1

  ro_or_rw_ext = {

    std::__1::atomic = {

      Value = 4295000136

    }

  }

  firstSubclass = nil

  nextSiblingClass = 0x00007ff8428edac8

}

(lldb) p $3.properties()

(const property_array_t) $5 = {

  list_array_tt = {

    = {

      list = {

        ptr = 0x00000001000081a8

      }

      arrayAndFlag = 4295000488

    }

  }

}

  Fix-it applied, fixed expression was:

    $3->properties()

(lldb) p $5.list

(const RawPtr) $6 = {

  ptr = 0x00000001000081a8

}

(lldb) p $6.ptr

(property_list_t *const) $7 = 0x00000001000081a8

(lldb) p *$7

(property_list_t) $8 = {

  entsize_list_tt = (entsizeAndFlags = 16, count = 2)

}

(lldb) p $8.get(0)

(property_t) $9 = (name = "name", attributes = "T@\"NSString\",C,N,V_name")

(lldb)

(lldb) p $8.get(1)

(property_t) $12 = (name = "hobby", attributes = "T@\"NSString\",C,N,V_hobby")

(lldb)

(lldb) p $3->methods()

(const method_array_t) $10 = {

  list_array_tt = {

    = {

      list = {

        ptr = 0x0000000100008090

      }

      arrayAndFlag = 4295000208

    }

  }

}

(lldb) p $10.list.ptr

(method_list_t *const) $11 = 0x0000000100008090

(lldb) p $10.list

(const method_list_t_authed_ptr) $13 = {

  ptr = 0x0000000100008090

}

(lldb) p $13.ptr

(method_list_t *const) $14 = 0x0000000100008090

(lldb) p *$14

(method_list_t) $15 = {

  entsize_list_tt = (entsizeAndFlags = 27, count = 7)

}

(lldb) p $15.get(0)

(method_t) $16 = {}

(lldb) p $15.get(0).big()

(method_t::big) $17 = {

  name = "satNB"

  types = 0x0000000100003f92 "v16@0:8"

  imp = 0x0000000100003ca0 (KCObjcBuild`-[LGPerson satNB])

}

(lldb) p $15.get(1).big()

(method_t::big) $18 = {

  name = "hobby"

  types = 0x0000000100003f8a "@16@0:8"

  imp = 0x0000000100003d30 (KCObjcBuild`-[LGPerson hobby])

}

(lldb) p $15.get(2).big()

(method_t::big) $19 = {

  name = "setHobby:"

  types = 0x0000000100003f9a "v24@0:8@16"

  imp = 0x0000000100003d60 (KCObjcBuild`-[LGPerson setHobby:])

}

(lldb) p $15.get(3).big()

(method_t::big) $20 = {

  name = "init"

  types = 0x0000000100003f8a "@16@0:8"

  imp = 0x0000000100003c10 (KCObjcBuild`-[LGPerson init])

}

(lldb) p $15.get(4).big()

(method_t::big) $21 = {

  name = "name"

  types = 0x0000000100003f8a "@16@0:8"

  imp = 0x0000000100003cd0 (KCObjcBuild`-[LGPerson name])

}

(lldb) p $15.get(5).big()

(method_t::big) $22 = {

  name = ".cxx_destruct"

  types = 0x0000000100003f92 "v16@0:8"

  imp = 0x0000000100003d90 (KCObjcBuild`-[LGPerson .cxx_destruct])

}

(lldb) p $15.get(6).big()

(method_t::big) $23 = {

  name = "setName:"

  types = 0x0000000100003f9a "v24@0:8@16"

  imp = 0x0000000100003d00 (KCObjcBuild`-[LGPerson setName:])

}

(lldb) p LGPerson.class

(Class) $1 = 0x0000000100008410

(lldb) p/x 0x0000000100008410+0x20

(long) $2 = 0x0000000100008430

(lldb) p (class_data_bits_t *)0x0000000100008430

(class_data_bits_t *) $3 = 0x0000000100008430

(lldb) p $3->data()

(class_rw_t *) $4 = 0x0000000100e59cb0

(lldb) p *$4

(class_rw_t) $5 = {

  flags = 2148007936

  witness = 1

  ro_or_rw_ext = {

    std::__1::atomic = {

      Value = 4295000448

    }

  }

  firstSubclass = 0x00000001000083e8

  nextSiblingClass = 0x00007ff85597aac8

}

(lldb) p $5.ro()

(const class_ro_t *) $6 = 0x0000000100008180

(lldb) p * $6

(const class_ro_t) $7 = {

  flags = 388

  instanceStart = 8

  instanceSize = 32

  reserved = 0

  = {

    ivarLayout = 0x0000000100003eb4 "\U00000003"

    nonMetaclass = 0x0000000100003eb4

  }

  name = {

    std::__1::atomic = "LGPerson" {

      Value = 0x0000000100003eb6 "LGPerson"

    }

  }

  baseMethods = {

    ptr = 0x00000001000081c8

  }

  baseProtocols = nil

  ivars = 0x0000000100008278

  weakIvarLayout = 0x0000000000000000

  baseProperties = 0x00000001000082e0

  _swiftMetadataInitializer_NEVER_USE = {}

}

(lldb) p $7.ivars

(const ivar_list_t *const) $8 = 0x0000000100008278

(lldb) p *$8

(const ivar_list_t) $9 = {

  entsize_list_tt = (entsizeAndFlags = 32, count = 3)

}

(lldb) p $9.get(0)

(ivar_t) $10 = {

  offset = 0x00000001000083a8

  name = 0x0000000100003f31 "subject"

  type = 0x0000000100003f78 "@\"NSString\""

  alignment_raw = 3

  size = 8

}

(lldb) p $9.get(1)

(ivar_t) $11 = {

  offset = 0x00000001000083b0

  name = 0x0000000100003f39 "_name"

  type = 0x0000000100003f78 "@\"NSString\""

  alignment_raw = 3

  size = 8

}

(lldb) p $9.get(2)

(ivar_t) $12 = {

  offset = 0x00000001000083b8

  name = 0x0000000100003f3f "_hobby"

  type = 0x0000000100003f78 "@\"NSString\""

  alignment_raw = 3

  size = 8

}

(lldb) p $9.get(3)

(lldb) p $9.get(0).big()



class


bits
ro


类结构


cache


cache_t


分析

struct class_rw_ext_t {

    DECLARE_AUTHED_PTR_TEMPLATE(class_ro_t)

    class_ro_t_authed_ptr<constclass_ro_t> ro;

    method_array_t methods;

    property_array_tproperties;

    protocol_array_t protocols;

    char*demangledName;

    uint32_tversion;

};

struct class_rw_t {

    // Be warned that Symbolication knows the layout of this structure.

    uint32_tflags;

    uint16_twitness;

#if SUPPORT_INDEXED_ISA

    uint16_t index;

#endif

    explicit_atomic ro_or_rw_ext;

    ClassfirstSubclass;

    ClassnextSiblingClass;

struct class_data_bits_t {

    friend objc_class;

   class_rw_t* data() const {

        return(class_rw_t*)(bits&FAST_DATA_MASK);

    }

struct objc_class : objc_object {

  objc_class(const objc_class&) = delete;

  objc_class(objc_class&&) =delete;

  void operator=(const objc_class&) = delete;

  void operator=(objc_class&&) = delete;

    // Class ISA;

    Classsuperclass;

    cache_tcache;            // formerly cache pointer and vtable

    class_data_bits_tbits;    // class_rw_t * plus custom rr/alloc flags

   class_rw_t *data() const {

        returnbits.data();

    }



23.类的结构里面为什么会有rw和ro以及rwe? 分值10分

(1)ro 属于 clean memory,在编译即确定的内存空间,只读,加载后不会改变内容的空间; (2)rw 属于 dirty memory,rw 是运行时结构,可读可写,可以向类中添加属性、方法等, 在运行时会改变的内存;

(3)rwe 

相当于类的额外信息,因为在实际使用过程中,只有很少的类会真正的改变他 们的内容,所以为避免资源的消耗就有了 rwe; (4)运行时,如果需要动态向类中添加方法协议等,会创建 rwe,并将 ro 的数据优先 attache 到 rwe 中,在读取时会优先返回 rwe 的数据,如果 rwe 没有被初始化,则返回 ro 的数据。

rw 中包括 ro 和 rwe,其中 rw 是 dirtymemory,ro 是 clean memory;为了让 dirty memory 占用更少的空间,把 rw 中可变的部分抽取出来为 rwe;

clean memory 

越多越好,dirty memory 越少越好,因为 iOS 系统底层虚内存机制的原 因,内存不足时会把一部分内存回收掉,后面需要再次使用时从硬盘中加载出来即 swap 机制,clean memory 是可以从硬盘中重新加载的内存,iOS 中的 macho 文件动态 库都属于此类行;dirty memory 是运行时产生的数据,这部分数据不能从硬盘中重新 加载所以必须一直占据内存,当系统物理内存紧张的时候,会回收掉 clean memory 内 存,如果 dirty memory 过大则直接会被回收掉;所以 clean memory 越多越好,dirty memory 越少越好;苹果对 rw、ro、rwe 进行这么细致的划分都是为了能更好更细致 的区别 cleanmemory 和 dirty memory;

24. cache 在什么时候开始扩容 , 为什么? 分值 10 分 1、一般情况下:如果当前方法 cache 之后,缓存的使用容量会超过总容量的 3/4,那么 此时就不会先插入,而是先触发扩容,扩容为原来的 2 倍,然后再插入本次的方法; 2、某些特殊预处理宏定义编译命令下,首次会存储满之后再开始扩容; 3、扩容时选用 3/4 作为负载因子是和 hash 表底层使用的链表以及红黑树的数据结 构有关,0.75 是最符合泊松分布概率计算得出的数值,在这个数值下哈希表的空间和 时间效率都是最高的;

25. objc_msgSend 为什么用汇编写 , objc_msgSend 是如何递归找到 imp? 分值

10分

(1)使用汇编响应速度快; (2)这个过程中使用了两个循环:

1.循环 1:通过前面获取的 mask,与要查找的_cmd 进行 hash 运算,获取下标,从而得到 _cmd 对应的 bucket 地址,然后进行向前平移查找,每次平移 16 个字节,如果找到对应 的 sel,则 cacheHit;当平移到 buckets 的首地址,依然没有查找到,则进入第二个循环; 2.循环 2:首先会获取末尾 bucket 的地址,同样采用向前查找的方式,向_cmd 对应的地 址进行平移查找。

一个类的类方法没有实现为什么可以调用 NSObject 同名对象方法 分值 10

分这里涉及到 isa 和 superclass 的走位以及方法查找逻辑。

首先类的 

isa 指向元类,在方法快速查找时,会根据类的 isa 找到元类,元类中没有该方 法,就会走到 lookUpImpOrForward 慢速查找流程中。在慢速查找流程中,会进行 for 递归查找,根据 superclass 查找到元类的父类,也就是根元类,而根元类的 superclass 指 向了 NSObject,所以会调用到 NSObject 的同名对象方法。

ISA_MASK = 0x00007ffffffffff8ULL 那么这个 ISA_MASK 的算法意义是 什么? 分值10分

这个算法主要是为了得到 isa 中存储的 class 信息,大部分 isa 都是不纯的 isa,是一个 长达 64 个 byte 位的联合体位域数据,而存储 class 信息的部分只有其中的部分 byte 位置,剩下的位置存储了其他的信息;读取的时候必须把其他无效位置的 byte 位数

据给遮盖住,所以需要使用 isa_mask,任何数据与 isa_mask 进行按位与操作,都只会 保留 isamask 对应 byte 位置的数据,这个算法的意义就是遮盖,盖住不需要的地方, 这样就能让 isa 存储更多的信息;分值 10 分


怎么打开汇编查看流程,有什么好处 ? 分值 10 分

1、通过 Xcode-debug-debug workflow-always show disassembly 可以查看汇编; 2、查看汇编可以从更深层了解当前函数的汇编层面的执行,为 objc 源码分析提供信 息避免方向性错误,结合 memory read 可以更清楚的看到寄存器之间是如何互相配合 处理配合的;使用汇编查看流程,可以在不确定源码出处和执行流程的情况下,跟踪内 部代码,并可以找到出处!同时,结合下符号断点的方式,能够更清晰的跟踪源码实 现。

分值10分

19.x/4gx和p/x以及p*$0代表什么意思 分值10分

x/4gx : 输出一段内存地址,以 8 字节的形式输出 4 段; p/x :输出一个数据结构的首地址;

p *$0 : $0 为指向某一个数据空间的指针,而该指令输出的是该数据的数据结构。

你可能感兴趣的:(类结构,objc_class)