美文网首页
对象本质 & isa解析

对象本质 & isa解析

作者: 囤囤fc | 来源:发表于2021-08-11 16:39 被阅读0次

之前我们分析了alloc流程内存对齐算法, 今天我们来研究对象的本质,并对isa进行详细解析。

对象的本质探究方法 - Clang

Clang是一个由苹果主导编写,基于LVVM的C/C++/OC编译器,通过Clang的rewrite命令可以将OC代码还原为源码
新建一个工程,在main函数中创建一个类,随意添加个属性:


image.png

打开终端,cd到文件所在目录,执行clang -rewrite-objc main.m -o main.cpp

  • 打开main.cpp文件,直接搜索FCPerson类名即可直接定位到我们要关注的位置,可以直接看到对象的本质是结构体
#ifndef _REWRITER_typedef_FCPerson
#define _REWRITER_typedef_FCPerson
typedef struct objc_object FCPerson;
typedef struct {} _objc_exc_FCPerson;
#endif

struct FCPerson_IMPL {
    struct NSObject_IMPL NSObject_IVARS;
    NSString *_fcName;
};
  • 其中objc_object就是NSObject的底层写法,_fcName是我们添加的属性,NSObject_IMPL就是isa:
struct NSObject_IMPL {
    Class isa;
};
  • 在下面还可以看到FCPerson的setter和getter方法:
static NSString * _I_FCPerson_fcName(FCPerson * self, SEL _cmd) { 
      return (*(NSString **)((char *)self + OBJC_IVAR_$_FCPerson$_fcName));
 }
static void _I_FCPerson_setFcName_(FCPerson * self, SEL _cmd, NSString *fcName) {
      (*(NSString **)((char *)self + OBJC_IVAR_$_FCPerson$_fcName)) = fcName; 
}

setter和getter在内存中读取属性的原理是什么?(*(NSString **)((char *)self + OBJC_IVAR_$_FCPerson$_fcName))是怎么找到fcName这个属性值的?
在取值时,系统只知道对象首地址,并不知道具体属性的地址信息。方法中(char *)self其实就是FCPerson对象的首地址,而OBJC_IVAR_$_FCPerson$_fcName则是fcName属性距离首地址的偏移量,系统就是通过首地址+偏移量的方式进行属性的读写的。

  • 接下来我们还可以看到很多类相关的结构体,method,protocol,ivar,class_ro_t,class_t
    等等,我也会在以后的文章中为大家做详细介绍,到目前为止,我们已经知道了对象的本质是结构体。

  • 之前在介绍alloc流程时,提到过在_class_createInstanceFromZone中可以看到将isa与cls绑定的代码:

if (!zone && fast) {
        obj->initInstanceIsa(cls, hasCxxDtor);
    } else {
        // Use raw pointer isa on the assumption that they might be
        // doing something weird with the zone or RR.
        obj->initIsa(cls);
    }

Isa解析

通过initIsa进入到objc_object::initIsa方法中,首先看到的就是isa的初始化方法isa_t newisa(0);,具体看一下isa_t的内部实现,删除掉多余代码后:

union isa_t {
    uintptr_t bits;

private:
    Class cls;

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

可以看到isa_t是一个联合体(联合体中成员互斥,即bits,cls,struct{ISA_BITFIELD}只能是其中一种),依次分析三个成员变量:

  • 苹果把isa根据需要进行了区分,苹果提出了TaggedPointer和NonpointerIsa。对于小对象采用TaggedPointet方式来存放其值。对于占用内存比较大的对象采用NonpointerIsa来把isa按位使用,一部分用来存放实际的对象地址,一部分存放附加的其他信息。

  • 对于NSDateNSNumber这样的小对象存储的值,绝大多数情况并不会大于20亿这个量级。如果采用指针、堆内存的方式,那势必会造成内存的浪费和性能损耗。苹果采用将value值直接存储在isa_t中的uintptr_t bits;上,并且用一些特殊标识来标明此isa是TaggedPoint类型的。这样用isa就存储了值,而不需要在堆上分配内存再去存储值。要知道堆内存的分配、释放及访问,要比栈内存慢很多的。

  • objc_object::initIsa方法中,可以看到如果不是nonpointer则会直接进行cls赋值newisa.setClass(cls, this);

  • struct{ISA_BITFIELD}ISA_BITFIELD是一个宏定义:

    image.png
    objc_object::initIsa方法中,如果是nonpointer的话,则会依次对ISA_BITFIELD中的属性进行赋值:
#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;

因此,如果是nonPointerIsa的话,isa已经不再是一个单纯只想cls的指针了,携带了很多附加信息。

遗留问题

通过探究源码得知,initIsa方法写死的创建非nonPointerIsa, initInstanceIsa和initClass创建的是nonPointerIsa,具体原因以后研究完会继续补充~

相关文章

  • 对象本质 & isa解析

    之前我们分析了alloc流程[https://www.jianshu.com/p/6650f5d973dc]和内存...

  • OC中类的本质

    OC中的对象的本质 对象本身是一个含有isa指针的结构体,isa指针指向对象所属的类类的本质:类本质也是一个结构体...

  • OC对象的本质

    OC对象的本质 一个对象的本质是一个结构体,结构体里面有isa指针、成员变量等,isa指针指向对象的类别,inst...

  • OC 与 Swift

    OC对象的本质(上):OC对象的底层实现原理OC对象的本质(中):OC对象的种类OC对象的本质(下):详解isa&...

  • OC对象的本质(中)—— OC对象的种类

    OC对象的本质(上):OC对象的底层实现原理OC对象的本质(中):OC对象的种类OC对象的本质(下):详解isa&...

  • OC对象的本质(下)—— 详解isa&supercl

    OC对象的本质(上):OC对象的底层实现原理OC对象的本质(中):OC对象的种类OC对象的本质(下):详解isa&...

  • ISA指向、类结构

    ISA指向、类结构 1.ISA指向 上次在对象本质和ISA指针[https://www.jianshu.com/p...

  • iOS底层解析-----从isa指针看继承关系

    在NSObject对象的本质中提到对象中都存在isa指针,那么问题一:对象的isa指针指向哪里?问题二:OC的类信...

  • 3-KVO本质

    1. 应用 2. 本质 当未给对象添加监听时,对象的isa指针指向它的类对象 当给对象添加监听时,对象的isa指针...

  • 四、isa 指针关联类

    主要内容:1.OC对象的本质2.isa 与 类的关联原理3.isa 与 类的关联验证 1.OC对象的本质 先了解编...

网友评论

      本文标题:对象本质 & isa解析

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