网络知识 娱乐 iOS 底层原理03——isa的走位图和类

iOS 底层原理03——isa的走位图和类

文章目录

  • 一、基本定义
  • 一、类对象的解析
  • 一、ISA指针指向解析
    • 1.
    • 2.
    • 3. 影响对象内存的因素
  • 二、元类的继承类关系
    • 1. 位域的定义
    • 2. 联合体的定义
    • 3. 结构体和联合体的区别
  • 三、内存平移的概念
    • 1. 要点
    • 2. 通过isa地址获取类对象的内存地址
  • 四、 实例方法、属性的存储位置分析
  • 五、问题
  • 六、用到的指令
  • 七、其它


一、基本定义

  • 类对象:即类,oc中用@interface 定义。大多数的类对象继承自NSObject. 参考iOS学习——iOS 整体框架及类继承框架图

一、类对象的解析

  • 类的本质:objc_class 结构体,也是一个对象
  • 类对象的ISA的指针指向元类。
  • 元类和类对象的名称是一样的。
  • 实例对象ISA --> 类对象ISA --> 元类对象 isa --> 根元类。

在这里插入图片描述

一、ISA指针指向解析

1.

2.

问题:内存优化是哪部分做的?操作系统来做的吗?苹果和windows都会优化吗?

  • 编译阶段通过重排成员属性的内存位置来优化内存。
  • 成员变量的顺序会对内存空间造成影响吗?只有在有父类的情况会有影响,子类没办法优化父类的内存空间。

3. 影响对象内存的因素

  • 成员变量
  • 单个类的成员变量顺序不会影响内存大小,系统会优化
  • 继承来的类,成员变量顺序会影响大小。
  • 8字节对齐的方式,内存对齐在编译阶段

二、元类的继承类关系

1. 位域的定义

  • 指明成员变量所占的位数。
  • ISA的struct就会使用位域来定义。
struct Teacher {
	char a : 7;
	char b : 2;
	char c : 7;
	char d : 2;
}t1; 
sizeof(t1) = 4;

2. 联合体的定义

  • 所有成员变量共用一片内存空间;
  • 每个成员变量都是可以访问这块内存;
  • 空间内存的大小取决于最大的成员变量,是最大成员变量(基本数据类型)内存的整数倍。
  • oc的源码当中当对于不同的平台的情况就会使用联合体。
union Teacher{
	char *name;// 指针8个字节
	int age;
	int height;
}t1;
sizeof(t1) = 8;
union Person{
	char a[7];// 7
	int b; // 4
}p1;
sizeof(p1) = 8;
// Object-C 源码
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;
public:
#if defined(ISA_BITFIELD)
    struct {
        ISA_BITFIELD;  // defined in isa.h
    };
    bool isDeallocating() {
        return extra_rc == 0 && has_sidetable_rc == 0;
    }
    void setDeallocating() {
        extra_rc = 0;
        has_sidetable_rc = 0;
    }
#endif
    void setClass(Class cls, objc_object *obj);
    Class getClass(bool authenticated);
    Class getDecodedClass(bool authenticated);
};

3. 结构体和联合体的区别

  • 结构体里面的变量能够共存,联合体里面的变量互斥,优化内存。

三、内存平移的概念

1. 要点

  • isa 指针和对象的关系?
  • 什么时候会和具体的对象(LGPerson)关联起来?什么方法来绑定的?
  • isTaggedPointer? 指针优化
  • 引用计数的值存储在isa指针里面,在后期的版本,之前的版本没有。(哪个版本?)
  • isa指针就是一个联合体(union)
  • nonPointIsa – 8个字节 – 8 * 8 == 64bits, 存放内存地址、引用计数

2. 通过isa地址获取类对象的内存地址

define ISA_BITFIELD                                                      
        uintptr_t nonpointer        : 1;                                       
        uintptr_t has_assoc         : 1;                                       
        uintptr_t weakly_referenced : 1;                                       
        uintptr_t shiftcls_and_sig  : 52;                                      
        uintptr_t has_sidetable_rc  : 1;                                       
        uintptr_t extra_rc          : 8

如下图所示,对于一个LGPerson的实例对象来说,它的内存空间以16进制打印出来前4个8字节内存空间,第一个八字节是isa的内存地址。如何通过isa的内存地址进行位运算得到实际的LGPerson的实例对象的内存地址呢?
位运算
如下图所示,在中间的值,就是实际的对象内存地址,通过将第一个8字节(ISA地址)先右移三位,把低三位清零,然后再左移12位,把左边的清零,最后再回到原来的位置,就可以得到对象具体的内存地址。 需要两边都清零,需要左移,又移来补0,清除两边的值。
ISA_BITFIELD 内存分配

四、 实例方法、属性的存储位置分析

  • new = alloc + init;
  • init就是一个工厂模式,NSObject 提供的一个公用接口。

五、问题

  • 所有编程语言的内存空间一定是8字节的整数倍吗?
  • 对象内存大小是16 的倍数是不是为了兼容优化过isa的对象和没优化过的对象,以前前8位isa只存类信息,后面8位存了现在的引用计数这些信息? 不是的,跟内存读取大小有关系。

六、用到的指令

LLDB打印指令:

  • p:详细数据
  • po:稍微少一些信息
  • x/4gx: 以16进制的形式打印4个八字节的内存空间
  • p/x: 以16进制的形式打印

七、其它

  • Link-Time Optimization: 编译器优化可能导致断点打不了。