ios 底层原理之alloc探究(二)

上一章节我们通过汇编跑流程找到 alloc 底层的核心方法 _class_createInstanceFromZone 本章主要研究当对象申请内存时到底如何去计算。

准备工作

1.了解基本数据类型占用字节数

ios 数组处理 ios数组底层实现_数据


2.了解LLDB 指令

ios 数组处理 ios数组底层实现_数据_02

数据的存储规律

ios 数组处理 ios数组底层实现_数据_03

内存对⻬的原则

1:数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第
一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要
从该成员大小或者成员的子成员大小(只要该成员有子成员
2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从
其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b
里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
3:结构体的总大小,必须是其内部最大成员的整数倍,不足补齐。
举例1:

struct Struct1 {
    double a;       // 8    [0 7]  【以第一个成员变量offset 为0的位置开始存储】。
    char b;         // 1    [8]       【char 需要1字节,也即是8必须是1的整数倍才能开始存储。】
    int c;          // 4    (9 10 11 [12 13 14 15] 【9,10,11 并不能整除4 所以数据c 存储从12位开始存储,】
    short d;        // 2    [16 17] 24 【当数据d 被存储完成后,此时总共所占用的字节是17,又因为结构体的总大小要保证是最大成员变量的整数倍,17/8=2......1 所以当前结构体的的大小为 24字节】
}struct1;

举例2:

struct Struct2 {
    double a;       // 8    [0 7]
    int b;          // 4    [8 9 10 11]
    char c;         // 1    [12]
    short d;        // 2    (13 [14 15] 16
}struct2; 通过计算可得结构大小为 16字节。

发现:当结构体中的成员变量的排列顺序不同,对应的存储大小也不相同。
疑问:刚才我们在上面打印person 时,我们也对位置以及顺序做过调整,但是发现 数据的存储很有规律,这是为什么呢?oc 做的优化,所以,我们平时在开发过程中对于对象的属性,并不需要排序。
举例3:

struct Struct3 {
    double a; // 8  [0-7]
    int b;    // 4  [8 ,9,10,11]
    char c;   // 1  [12]
    short d;  // 2  (13 [14 ,15]
    int e;    // 4  [16,17,18,19]
    struct Struct1 str;  // 24 (21 ,22,23 [24 ,48] 
}struct3; 【48】

【这里为什么从24位开始,因为通过对齐原则发现:struct1为结构体,所以要找该结构体最大的成员变量(即8字节的整数倍开始存储)24 开始,接下来同样按照单个成员去排列,相当于把str的元素罗列到struct3 int e 下面 继续排列,只是有一点注意,当出现结构体为成员时,要以子结构体中的最大成员对齐第一个元素,所以struct3最终大小为48】

为什么要遵循内存对齐原则?

我们一个一个去取不香吗?就好比举例1:

struct Struct1 {
    double a;       // 8    [0 7]
    char b;         // 1    [8]
    int c;          // 4    (9 10 11 [12 13 14 15]
    short d;        // 2    [16 17] 24
}struct1;

如果我们就按照顺序存入数据 其实只需要 15个字节,反而遵循原则后又变大了,为什么呢?其实我们对于数据的操作不光光只考虑存入,最关键的是读取。电脑在对数据的处理方面并不能像人一样灵活,只能通过程序去控制。(按照以剩余最大的数取)
假设,我们就按照 8,1,4,2 这个顺序去存储,那么计算机如何去读取呢?
第一次:肯定是用8个字节长度去读,第二次,用4个字节长度去读,但是读取不到,然后程序会告诉他用1个字节长度去读,第三次读取成功,以此类推,读完共需要 7次在能把所有的数据读完。
但是如果按照内存对齐原则需要读几次呢?第一次我以8去读,第三次以4去读这时我们的1能不能读出来呢?答案能,因为,我们在存入4的时候,是不是空了三个,正好加上1就是是四个长度,能把1取出来,4也是一次取出,2也是共需要4次取出全部数据。
相差近一倍的读取效率。那为什么空出的刚好和旁边的数据储存能拼在一起呢?
在看基本数据的存储需要的字节,1,2,4,8 2的0 ,2的1 2的2 2的3 所以这四个数有对应的排列组合规律。
结论:通过遵循内存对齐原则,大大的缩短的读取时间(以空间换时间),加快程序优化。

为什么对象以16字节对齐,但成员变量确以8字节对齐?

在上一章我们了解到对象在申请内存的时候是以16字节对齐,因为成员变量以8字节对齐更能提高读取效率(因大部分成员变量都是8字节,所以效率更高,那为什么不用16字节对齐,大部分都是8字节,如果用16字节,将造成大量的空间浪费),那为什么对象要用16字节对齐呢?不能用8字节对齐吗?8字节对齐肯定是可以的。那我们就先讲讲以八字节对齐,

看图解。

ios 数组处理 ios数组底层实现_数据_04

那就先到这,未完待续。。。