日记1- 类 对象 isa 内存 相关原理总结

189 阅读5分钟

Day 1

1. 对象的原理 

   1.main函数启动前 :

  • dyld启动 加载动态库、共享内存、全局C++对象的构造函数的调用、一系列的初始化、dyld注册回调函数
  • libsystem 的初始化 libSystem_initializer
  • libdispatch_init 队列环境的准备
  • _os_object_init 过渡到 _objc_init
  • `_dyld_objc_notify_register` 镜像文件的映射
  • 1类-2分类-3属性-4协议-5SEL-6方法 的加载
  • 展开分析 Runtime 各个部分的原理
  • main函数的启动

2. 内存字节对齐原则
1. 16字节对齐之前,首先需要了解内存字节对齐的原则

  结构体的整体对齐规则:结构体的总大小,即sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐.
2. 为什么需要16字节对齐

  • 提高性能,加快存储速度: 通常内存是由一个个字节组成,cpu在存储数据时,是以固定字节块为单位进行存取的.这是一个以空间换时间的一种优化方式,这样不用考虑字节未对齐的数据,极大节省了计算资源,提升了存取速度。
  • 更安全 由于在一个对象中,第一个属性isa8字节,当然一个对象可能还有其他属性,当无其他属性时,会预留8字节,即16字节对齐.因为苹果公司现在采用的16字节对齐(早期是8字节对齐--objc4-756.2及以前版本),如果不预留,就相当于这个对象的isa和其他对象的isa紧挨着,在CPU存取时它以16字节为单位长度去访问的,这样会访问到相邻对象,容易造成访问混乱,那么16字节对齐后,可以加快CPU读取速度,同时使访问更安全,不会产生访问混乱的情况

3. 总结:

  • 对象的开辟内存交由 alloc 方法封装

  • init 只是一种工厂设计方案,为了方便子类重写:自定义实现,提供一些初始化就伴随的东西

  • new 封装了 alloc 和init

  • 对象的属性是按照8字节进行对齐的

  • 对象本身则是按照16字节进行对齐的

    • 因为内存是连续的,通过 16 字节对齐规避了风险和容错,有效的防止了访问溢出

    • 同时,也提高了寻址访问效率,也就是通常我们所说的空间换时间

day2

1. 通过编译了解

  • NSObject的底层实现其实就是一个包含一个isa指针的结构体.
  • Class其实就是一个指针,指向了objc_class类型的结构体.
  • Demo中对象 TCJPerson_IMPL结构体内有三个成员变量:
    • isa 继承自父类NSObject
    • helloName
    • _name

对于属性name:底层编译会生成相应的setter、getter 方法,及_name

对于成员变量helloName:底层编译不会生成

  • NSObject定义中isa的类型是Class,其根本原因是由于isa对外反馈的是类信息,为了让开发人员更加清晰明确,需要在isa返回时做了一个类型强制转换,类似于swift中的 as 的强转.isa_t类型初始化的 -> Class

2. 当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union)

3. 类在内存中只会存在一份,对象可以创建多个

其实和实例对象一样,都是由上级实例化出来的——类的上级叫做元类.

isa走位(虚线):实例对象-> 类对象 -> 元类 -> 根元类 -> 根元类(本身指向自己)

继承关系 :1.根元类 的 父类指向 根类 也就是 NSObject,

NSObject父类为nil,

每个Meta classisa指针都指向Root class (meta)

  • instance对象的isa指向class对象
  • class对象的isa指向meta-class对象
  • meta-class对象的isa指向基类的meta-class对象

day 3. 

1. 类的本质: 类的本质是objc_class类型的结构体,objc_class继承于objc_object,所以满足万物皆对象

  • 其实NSObjectobjc_object的仿写,和objc_object的定义是一样的,在底层会编译成objc_object

  • 同理NSObject类OC版本的objc_class

  • 1. 所有的Class,isa指针的类型,都是以 objc_class 为模板创建的

  • 2.  而objc_class是一个结构体.

  • 3. objc_class 结构体类型是继承自 objc_object

 objc_object也是一个结构体,且有一个isa属性,所以objc_class也拥有了isa属性

2. 总结 类与对象的本质:

  • 所有的对象 + 类 + 元类 都有isa属性
  • 所有的对象都是由objc_object继承来的
  • 简单概括就是万物皆对象,万物皆来源于objc_object,有以下两点结论:
    • 所有以 objc_object为模板创建的对象,都有isa属性
    • 所有以 objc_class为模板创建的,都有isa属性
  • 在结构层面可以通俗的理解为上层OC底层的对接:
    • 下层是通过 结构体 定义的 模板,例如objc_class、objc_object

    • 上层是通过底层的模板创建的一些类型,例如TCJPerson

3. 类的结构

  1. 从objc_class的定义可以得出,类有4个属性:isa、superclass、cache、bits

ISA

 不但实例对象中有isa指针

类对象中也有isa指针关联着元类

Class本身就是一个指针,占用8字节

Class superclass

类的父类(一般为NSObjectsuperclassClass类型,所以占用8字节

cache_t cache

cache_t缓存的是方法

class_data_bits_t bits

2. 什么是 属性 & 成员变量 & 实例变量 ?

  • 属性(property):在OC中是通过@property开头定义,且是带下划线成员变量 + setter + getter方法的变量

  • 成员变量(ivar):在OC的类中{}中定义的,且没有下划线的变量

  • 实例变量:通过当前对象类型,具备实例化的变量,是一种特殊的成员变量,例如 NSObject、UILabel、UIButton等,    成员变量和实例变量 区分就是 实例变量是对象有属性

3. isKindOfClass : 是元类 及 父类,或者类

    isMemberOfClass : 是类本身  或者  元类,  比kind少父类

4. strong & copy & weak 底层分析

  • copystrong修饰的属性在底层编译的不一致,主要还是llvm中对其进行了不同的处理的结果.copy的赋值是通过objc_setProperty,而strong的赋值时通过self + 内存平移(即将指针通过平移移至name所在的位置,然后赋值),然后还原成 strong类型
  • strong & copy 在底层调用objc_storeStrong,本质是新值retain,旧值release
  • weak 在底层调用objc_initWeak