zoukankan      html  css  js  c++  java
  • Runtime之IMP指针,isa指针

    要了解 isa 指针先了解下类的定义
    在xcode中用快捷键Shift+Cmd+O 搜索objc.h 能看到类的定义:
    了解


    Paste_Image.png

    可以看出:
    objc_object:Objective-C对对象的定义, 其质上是结构体对象,其中 isa是它唯一的私有成员变量,即所有对象都有isa指针
    Class 是一个 objc_class 结构类型的指针
    id是一个 objc_object 结构类型的指针,这也是id可以指向任何对象的原因
    SEL(方法选择器)是一个objc_selector结构类型的指针
    IMP 先不提

    再搜runtime.h


    Paste_Image.png

    每个对象结构体的首个成员是Class类的变量,该变量定义了对象所属的类,通常称为isa指针

    super_class:父类,如果该类已经是最顶层的根类,那么它为NULL。
    version:类的版本信息,默认为0
    info:供运行期使用的一些位标识。
    instance_size:该类的实例变量大小
    ivars:成员变量的数组
    struct objc_method_list **methodLists OBJC2_UNAVAILABLE : 方法列表,类目就是通过它添加方法的

    struct objc_cache *cache OBJC2_UNAVAILABLE : 方法缓存,对象接到一个消息会根据isa指针查找消息对象,这时会在methodLists中遍历,如果cache了,常用的方法调用时就能够提高调用的效率。

    struct objc_protocol_list *protocols OBJC2_UNAVAILABLE : 协议链表

    isa 指针优化(NONPOINTER_ISA)

    用 64 bit 存储一个内存地址显然是种浪费,毕竟很少有那么大内存的设备。于是可以优化存储方案,用一部分额外空间存储其他内容。isa 指针第一位为 1 即表示使用优化的 isa 指针,这里列出不同架构下的 64 位环境中 isa 指针结构:

    union isa_t 
    {
        isa_t() { }
        isa_t(uintptr_t value) : bits(value) { }
        Class cls;
        uintptr_t bits;
    #if SUPPORT_NONPOINTER_ISA
    # if __arm64__
    #   define ISA_MASK        0x00000001fffffff8ULL
    #   define ISA_MAGIC_MASK  0x000003fe00000001ULL
    #   define ISA_MAGIC_VALUE 0x000001a400000001ULL
        struct {
            uintptr_t indexed           : 1;
            uintptr_t has_assoc         : 1;
            uintptr_t has_cxx_dtor      : 1;
            uintptr_t shiftcls          : 30; // MACH_VM_MAX_ADDRESS 0x1a0000000
            uintptr_t magic             : 9;
            uintptr_t weakly_referenced : 1;
            uintptr_t deallocating      : 1;
            uintptr_t has_sidetable_rc  : 1;
            uintptr_t extra_rc          : 19;
    #       define RC_ONE   (1ULL<<45)
    #       define RC_HALF  (1ULL<<18)
        };
    # elif __x86_64__
    #   define ISA_MASK        0x00007ffffffffff8ULL
    #   define ISA_MAGIC_MASK  0x0000000000000001ULL
    #   define ISA_MAGIC_VALUE 0x0000000000000001ULL
        struct {
            uintptr_t indexed           : 1;
            uintptr_t has_assoc         : 1;
            uintptr_t has_cxx_dtor      : 1;
            uintptr_t shiftcls          : 44; // MACH_VM_MAX_ADDRESS 0x7fffffe00000
            uintptr_t weakly_referenced : 1;
            uintptr_t deallocating      : 1;
            uintptr_t has_sidetable_rc  : 1;
            uintptr_t extra_rc          : 14;
    #       define RC_ONE   (1ULL<<50)
    #       define RC_HALF  (1ULL<<13)
        };
    # else
        // Available bits in isa field are architecture-specific.
    #   error unknown architecture
    # endif
    // SUPPORT_NONPOINTER_ISA
    #endif
    };

    SUPPORT_NONPOINTER_ISA 用于标记是否支持优化的 isa 指针,其字面含义意思是 isa 的内容不再是类的指针了,而是包含了更多信息,比如引用计数,析构状态,被其他 weak 变量引用情况。判断方法也是根据设备类型:

    #if !__LP64__  ||  TARGET_OS_WIN32  ||  TARGET_IPHONE_SIMULATOR  ||  __x86_64__
    #   define SUPPORT_NONPOINTER_ISA 0
    #else
    #   define SUPPORT_NONPOINTER_ISA 1
    #endif

    isa指针会判断是否支持 TaggedPointer 支持会直接将其指针值作为引用计数返回

    TaggedPointer 就是一种优化方式,当承载内容小于8字节时,指针直接储存承载内容

    关于Tagged Pointer 这里有详细介绍
    http://www.infoq.com/cn/articles/deep-understanding-of-tagged-pointer/

    如果当前设备是 64 位环境并且使用 Objective-C 2.0(5s之后就都是64位),那么“一些”对象会使用其 isa 指针的一部分空间来存储它的引用计数;否则 Runtime 会使用一张散列表来管理引用计数

    64位中isa 指针中变量对应的含义:


    Paste_Image.png

    associate object : 关联对象

    IMP 指针


    Paste_Image.png

    SEL会依据方法名生成唯一的表示作为key ,便于查找

    IMP指针是指向实现函数的指针,通过SEL取得IMP,objc_msgSend来执行实现方法

    objc_msgSend函数在执行方法时不会直接在 isa 指针指向的类的方法列表中遍历查找能够响应的方法,因为每次都要查找效率太低了,而是优先在缓存(方法列表)中查找,若是找不到再沿着继承体向上查找。每次匹配到的结果会缓存在"快速映射表"里,来提高效率,同时objc_msgSend函数用到了"尾调用优化技术",来节约资源,感兴趣可以了解下
    https://en.wikipedia.org/wiki/Tail_call
    http://kb.cnblogs.com/page/518771/


    //引用文章
    http://www.cocoachina.com/ios/20151209/14636.html
    http://www.cocoachina.com/ios/20150717/12623.html
    http://www.cnblogs.com/ioshe/p/5489086.html

  • 相关阅读:
    JSTL学习总结
    Spring 3 MVC: Create Hello World Application In Spring 3.0 MVC(reprint)
    如何查询端口号被哪个程序占用?
    php 共享内存
    php 消息队列
    php 快速fork出指定个子进程
    批量 kill mysql 中运行时间长的sql
    socket发送http请求
    TCP/IP、Http、Socket的区别
    文本协议和二进制协议
  • 原文地址:https://www.cnblogs.com/LifeTechnologySupporter/p/6741943.html
Copyright © 2011-2022 走看看