iOS底层探索二-对象原理(中)
一、字节
字节(Byte)是计算机信息技术用于计量存储容量的一种计量单位,也表示一些计算机编程语言中的数据类型和语言字符。Byte是从0-255的无符号类型,所以不能表示负数。
C++ 基本数据类型所占内存大小(字节数)
二、对象内存大小的影响因素
准备工作:定义一个类:Person,并且通过 runtime 方法: class_getInstanceSize()获取初始化内存大小
1、属性
Person 类中添加属性name属性,并获取添加属性后类的内存大小
添加属性:
内存大小:
添加属性后Person类的内存大小由原来的8字节增加到16字节,说明属性对类的内存大小会产生影响。
2、成员变量
Person 类中添加属性成员变量,并获取添加属性后类的内存大小
添加成员变量:
内存大小:
添加成员变量后Person类的内存大小由原来的8字节增加到16字节,说明成员变量对类的内存大小会产生影响。
3、方法
Person 类中添加方法,并获取添加属性后类的内存大小
添加方法:
内存大小:
添加方法后Person类的内存大小是8字节,说明方法对类的内存大小不会产生影响。
4、类方法
Person 类中添加属类方法,并获取添加属性后类的内存大小
添加类方法:
内存大小:
添加类方法后Person类的内存大小是8字节,说明类方法对类的内存大小不会产生影响。
总结:属性和成员变量对类的内存大小产生影响。因为属性编译过后也是以成员变量的方式存在,所有也可以说成员变量才会对类的内存大小产应影响
三、 内存对齐原则
数据成员对齐:结构体(struct)或联合体(union)的数据成员,第一个数据成员放在offset 为0的地方,以后每个数据成员储存的起始位置要从改成员大小或者成员的子成员大小(只要改成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int为4字节,则要从4的整数倍地址开始存储)
结构体对齐:如果一个结构体里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始储存。(struct a 包含 struct b, struct b={char, int, double},b应该从8的这数倍开始储存。)
结构体的总大小,也就是sizeOf() 的结果,必须是其内部最大成员的整数倍,不足的要补齐。
1、 结构体运算:
Struct1 和 Struct2 元素相同,内存大小却不相同。根绝内存规则计算,看这两个结构体内存大小是否相同。
Struct1计算:
Struct2计算:
根据上面结构体计算发现:相同类型元素,不同排序的结构体,内存大小是不一样的。
那么日常开发中需要特意的排序吗? 是不需要的,编译器会自动优化,调整位置。
2、类计算:
Person 类中添加属性,并获取添加属性后类的内存大小
添加属性:
内存大小:
sizeof:是一个运算符,获取的是类型的大小(int、size_t、结构体、指针变量等),程序编译时获取class_getInstanceSize:是一个函数,创建的对象加所有实例变量实际占用的内存大小,程序运行时获取malloc_size:在堆中开辟的大小,向系统申请的空间大小 根据结构体的运算规则:sizeof方法获取person对象的指针,内存大小是8。class_getInstanceSize成员变量所需内存大小是32字节,因为类中含有隐藏变量isa指针,一个指针内存大小是8字节,所有内存大小是40字节。但是为什么向系统申请内存空间大小的时候却是48字节呢?
四、malloc_size
1、segregated_size_to_fit
static MALLOC_INLINE size_t
segregated_size_to_fit(nanozone_t *nanozone, size_t size, size_t *pKey)
{
size_t k, slot_bytes;
if (0 == size) {
size = NANO_REGIME_QUANTA_SIZE; // Historical behavior
}
// #define NANO_REGIME_QUANTA_SIZE (1 << SHIFT_NANO_QUANTUM) // 16
// #define SHIFT_NANO_QUANTUM 4
k = (size + NANO_REGIME_QUANTA_SIZE - 1) >> SHIFT_NANO_QUANTUM;
// #define SHIFT_NANO_QUANTUM 4
slot_bytes = k << SHIFT_NANO_QUANTUM;
*pKey = k - 1;
return slot_bytes;
}
segregated_size_to_fit 是 malloc_size 计算内存大小的核心方法,可以计算出slot_bytes的大小:
所有结构体内部元素(成员变量)是8字节对齐,而堆区的申请内存大小是16字节对齐。