线程的内存模型,进程的内存模型

  线程的内存模型,进程的内存模型

  Objective-C是一种通用的、高级的、面向对象的编程语言。它扩展了标准的ANSI C编程语言,并在ANSI C中加入了Smalltalk风格的消息传递机制。

  可以理解为Objective-C=C Runtime,这是C语言拥有面向对象功能的驱动力,是iOS开发中的核心概念。我们可以在苹果的开源运行时(最新版objc4-779.1.tar.gz)中找到Objective-C对象模型的一些实现细节。

  NSObject的实现:OC中几乎所有的类都继承自NSObject,OC的动态也是通过NSObject实现的,所以要从NSObject入手。

  在NSObject.h运行时源代码中,我们可以找到NSObject的定义:

  @ interface ns object ns object { Class ISA OBJC _ ISA _ avail ability;}可以看到NSObject中有一个指向Class的isa,其中Class的定义在objc.h:

  ///表示Objective-C类的不透明类型。

  typedef struct objc _ class * Class

  ///表示类的实例。

  结构对象_对象{

  class _ Nonnull ISA OBJC _ ISA _ avail ability;

  };

  Objc_class代表类对象,objc_object代表实例对象,objc_object的isa指向objc_class。可以得出结论,实例对象的isa指向类(类对象)。其实类(objc_class)也有isa属性,那么它指向什么呢?

  元类(Meta Class)这里运行时为了设计的统一性,引入了元类的概念。

  当调用对象的实例方法时,方法的实现通过对象的isa在类中获得。当一个类对象的类方法被调用时,该方法的实现通过该类的isa在元类中获得。

  objc_class的Isa指向元类,甚至元类也有isa指针,指向根元类。实例、类对象、元类和根元类之间的关系如下图所示:

  和元类形成了一个完整的闭环,其中有两个关系需要注意:

  类的isa都指向根元类,根元类指向自身。根元类继承了根类(NSObject)的ns object)object 1.0数据模型。我们可以在runtime.h中检查objc_class的定义

  结构对象_类{

  class _ Nonnull ISA OBJC _ ISA _ avail ability;

  #如果!__OBJC2__

  class _ Nullable super _ class objc 2 _ UNAVAILABLE;

  const char * _ non null name objc 2 _ UNAVAILABLE;

  长版OBJC2 _不可用;

  long info OBJC2 _ UNAVAILABLE

  long instance _ size objc 2 _ UNAVAILABLE;

  struct objc _ ivar _ list * _ Nullable ivars objc 2 _ UNAVAILABLE;

  struct objc _ method _ list * _ Nullable * _ Nullable method lists objc 2 _ UNAVAILABLE;

  struct objc _ cache * _ Nonnull cache objc 2 _ UNAVAILABLE;

  struct objc _ protocol _ list * _ Nullable protocols obj C2 _ UNAVAILABLE;

  #endif

  } OBJC2 _不可用;

  /*使用“Class”而不是“struct objc_class *` */

  注意这两个宏命令:__OBJC2__和OBJC2_UNAVAILABLE,都是为了表示当前的objc_class结构是OBJC2之前的结构设计,也就是Objc1.0的设计

  从objc_class的定义中我们可以看到,它包含了超类的指针(super_class)、类名(name)、实例大小(instance_size)、objc_ivar_list成员变量列表的指针(ivars)和指向objc_method_list指针的指针(methodLists)。

  注意*methodLists是一个指向方法列表的指针,您可以动态修改*methodLists的值来添加成员方法。这也是Category实现的原理,也解释了为什么Category不能添加属性。

  剩下的对象缓存代表函数的缓存列表,对象协议列表代表协议列表。

  目标语言历史我在网上查资料的时候发现关于运行时间的文章非常多,但提示数据模型在OC1.0和2.0之间区别的非常少,其实这一点很重要的。这也是为什么我将这段标题命名为目标-C1.0数据模型的原因。

  这里补一点目标-丙语言的发展历史(维基百科):

  目标-C1.0即目标-丙由楼梯石级公司的布莱德考克斯(布拉德考克斯)和汤姆洛夫(汤姆洛夫)在1980 年代发明。它是(同地面控制中心)地面控制中心的一个前端,它可以编译混合C与目标-丙语法的源文件106 .目标-丙是C的扩展,类似于目标-丙是C的扩展。

  目标-C2.0在2006年七月苹果全球开发者会议中,苹果宣布了"目标-C 2.0英寸的发布,其增加了"现代的垃圾收集,语法改进,运行时性能改进,以及64位支持"。

  目标2.0数据模型可以在objc-runtim-new.h文件找到新版对对象_类的数据模型定义:

  结构对象类:对象对象

  //Class ISA;

  类超类;

  cache _ t cache//以前的缓存指针和虚函数的类创建一个表

  类_数据_位_t位;//class_rw_t *加上自定义rr/alloc标志

  class_rw_t *data()常量{

  返回位。data();

   }

  }

  结构对象_对象{

  私人:

  isa _ t isa

  }

  联合isa_t

  {

  isa_t() { }

  isa_t(uintptr_t值) :位(值){ }

  清屏类;

  uintptr_t位;

  }

  会发现对象_类不再是一个单独的结构体,而是继承于对象对象,对象对象内部的伊萨变成了isa_t的联合体。

  classdatabits_t我们再回来看类中的其他属性,之前表示类的属性、方法、以及遵循的协议都放在了类_数据_位_t中,更准确的说是放在了第一课。

  struct class_data_bits_t {

  朋友对象_类

  //值是上面的快速标志.

  uintptr_t位;

  class_rw_t* data()常量{

  return(class _ rw _ t *)(bits FAST _ DATA _ MASK);

   }

  }

  struct class_rw_t {

  //注意符号化知道这个结构的布局。

  uint32_t标志;

  uint16_t版本;

  uint16_t见证;

  const class _ ro _ t * ro

  方法_数组_t方法;

  属性_数组_t属性;

  协议_阵列_测试协议;

  }

  struct class_ro_t {

  uint32_t标志;

  uint32 _ t instanceStart

  uint32 _ t实例大小

  #ifdef __LP64__

  uint32_t保留;

  #endif

  const uint8 _ t * ivarLayout

  常量字符*名称

  method _ list _ t * baseMethodList

  协议_列表_ t *基础协议

  const ivar _ list _ t * ivars

  const uint8 _ t * weakIvarLayout

  property _ list _ t *基本属性;

  }

  这里面引入了类_rw_t和class_ro_t(读写,只读)两个结构体。可以看到类_rw_t是包含一个常量指针ro,结构体为class_ro_t。这里存储了当前类在编译期就已经确定的属性、方法以及遵循的协议。在中国运行时的时候会调用实现类方法,将class_ro_t传入class_rw_t,所以新版的动态性是通过这种方式实现的。

  cache_t结构cache_t

  静态bucket _ t *空桶();

  struct bucket _ t * buckets();

  mask _ t mask();

  mask _ t occupated();

  }

  struct bucket_t {

  //IMP-first对arm64e ptrauth更好,对arm64也不差。

  //SEL-first更适合armv7*和i386以及x86_64。

  #if __arm64__

  explicit _ atomic uintptr _ t _ imp

  explicit _ atomic SEL _ sel

  #否则

  explicit _ atomic SEL _ sel

  explicit _ atomic uintptr _ t _ imp

  #endif

  }

  Cache_t是objc_class中的缓存结构,通过bucket_t结构存储一些最近调用的函数。设置缓存的最大原因是OC是一种动态语言,函数的执行是通过消息调用来实现的。消息调用会先在当前类中查找方法列表,如果找不到,就会查找父类。直到检索NSObject找不到函数实现,才会进入消息转发流程。为了节省每次查找函数表的成本,发明了cache_t。我们从bucket_t的内联函数可以看出,缓存的SEL和IMP都是加载到内存中的。

  方法_t结构方法_t {

  SEL名称;

  const char *类型;

  MethodListIMP imp

  结构SortBySELAddress:

  public STD:binary _ function const method _ t

  const方法_t,bool

   {

  bool运算符()(const method_t lhs,

  const方法_t rhs)

  { return lhs . name RHS . name;}

   };

  };

  这是函数的结构,它包含三个成员变量。SEL是方法名的名称。Types是一个类型代码,类型可以称为类型编码。IMP是一个函数指针,指向一个函数的具体实现。运行时消息传递和转发的目的是发现IMP和执行函数。

  数据的比较。最后,Objc1.0和2.0的对比:

  这两张图片引自沈晗的博客。

  注意:由于引用的运行时版本不一致,可能会有一些差异,但都是一致的。

  要深入分析ObjC中的方法,请参考链接。结构神经医院Objective-C运行时间为入院第一天—— isa和Class。

  转载请联系作者获得转载授权,否则将追究法律责任。

郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。

相关文章阅读

  • office2010激活密钥大全 怎么永久激活office2010
  • project2010产品密钥免费_project2010激活密钥永久激活码
  • c语言调用退出函数 c语言退出整个程序怎么写
  • c语言中怎么给函数初始化 c语言的初始化语句
  • c语言编写函数计算平均值 c语言求平均函数
  • chatgpt是什么?为什么这么火?
  • ChatGPT为什么注册不了?OpenAI ChatGPT的账号哪里可以注册?
  • OpenAI ChatGPT怎么注册账号?ChatGPT账号注册教程
  • chatgpt什么意思,什么是ChatGPT ?
  • CAD中怎么复制图形标注尺寸不变,CAD中怎么复制图形线性不变
  • cad中怎么创建并使用脚本文件,cad怎么运行脚本
  • cad中快速计算器的功能,cad怎么快速计算
  • cad中快速修改单位的方法有哪些,cad中快速修改单位的方法是
  • cad中心点画椭圆怎么做,cad轴测图怎么画椭圆
  • CAD中常用的快捷键,cad各种快捷键的用法
  • 留言与评论(共有 条评论)
       
    验证码: