iOS底层之 内存对齐

数据类型大小

首先附上C和OC,各数据类型的大小表。

C OC 32位 64位
bool BOOL(64位) 1 1
signed char (__signed char)int8_t、BOOL(32位) 1 1
unsigned char Boolean 1 1
short int16_t 2 2
unsigned short unichar 2 2
int int32_t、 NSInteger(32位)、boolean_t(32位) 4 4
unsigned int boolean_t(64位)、 NSUInteger(32位) 4 4
long NSInteger(64位) 4 8
unsigned long NSUInteger(64位) 4 8
long long int 64_t 8 8
float CGFloat(32位) 4 4
double CGFloat(64位) 8 8

为什么要做内存对齐

如下图,|-|表示自然边界,假设存在两个连续的位于自然边界上的64位数据,当CPU访问它们中的任何一个的时候,可以一条LD指令就能完成加载:
  |-|BBBBBBBB|-|BBBBBBBB
现在假设有一个8字节数据如下,|表示数据开始位置,|-|表示自然边界:
  |-|BBBBB|BBB|-|BBBBB|BBB
其前三字节为前一个对齐的八字节数据的后三字节,其后五字节为后一个对齐的八字节数据的前五字节。
对于不支持非对齐装载指令的CPU来说,要装载这样的一个数据,需要先装载前一个八字节数据,再装载后一个八字节数据,然后将前一个八字节数据的后三字节与后一个八字节数据的前五字节数据合并才能得到结果,与对齐数据的访问相比,多了一个装载指令以及相关合并指令的开销,一般来说,在忽视缓存未命中的情况下,装载指令的执行与得到结果之间是存在额外开销的,因此这个差别是很大的,何况上边说的,假设是在操作系统对CPU异常进行处理时为其加载数据,那么异常处理程序的开销可能更大;对非对齐数据的写入时也需要额外的加载,合并操作。即使对于支持非对齐数据加载的CPU,依然会极大的影响效率,差别只是它省略掉了CPU异常处理过程。
  再进一层,假设之前描述的非对齐数据刚好横跨两个cache line,而且这两个cache line至少有一个不在cache中(虽然对齐数据也会存在未命中,但是与非对齐相比,它不会横跨两个cache line),那么这个访问效率绝对不是多几十条指令的问题了。因此,内存不对齐的坏处不是浪费内存,因为即使我写一个随便在不同位置放置不同大小的数据结构时,只要告诉编译器说必须按照一字节对齐,编译器编译时肯定按照我的意愿不浪费一个字节的内存。编译器默认按照自然边界对齐,是因为它要求效率,保证程序的正常运行(因为非对齐访问可能导致进程退出)。我们对结构体的组织的调整是为了节约内存,而调整的规则就是按照内存对齐来安插数据。

内存对齐的规则

  • 数据成员对⻬规则:结构(struct)(或联合(union))的数据成员,第
    ⼀个数据成员放在offset为0的地⽅,以后每个数据成员存储的起始位置要
    从该成员⼤⼩或者成员的⼦成员⼤⼩(只要该成员有⼦成员,⽐如说是数组,
    结构体等)的整数倍开始(⽐如int为4字节,则要从4的整数倍地址开始存
    储;
  • 结构体作为成员:如果⼀个结构⾥有某些结构体成员,则结构体成员要从
    其内部最⼤元素⼤⼩的整数倍地址开始存储.(struct a⾥存有struct b,b
    ⾥有char,int ,double等元素,那b应该从8的整数倍开始存储.);
  • 收尾⼯作:结构体的总⼤⼩,也就是sizeof的结果,.必须是其内部最⼤
    成员的整数倍.不⾜的要补⻬。

是不是很抽象?是不是很无语?看的是不是很困?其实我也是。。
稍微皮一下。。

下面就来做一下图文解析。。


15996337662730.jpg

开篇的时候,就已经附上了一个数据类型大小的表格,double占8字节、char占1字节、int占4字节、short占2字节。

  • 第一个数据成员a,从offset为0的位置开始存储,共8个字节;
  • 第二个数据成员b,从offset为8的位置开始存储,是char类型大小1的倍数,所以可以直接存储1个字节;
  • 第三个数据类型c,从offset为9的位置开始,但是由于9并不是int类型大小4的倍数,所以需要从后面的位置12开始存储四个字节,即12-15的位置;(上述规则1)
  • 第四个数据类型d,从offset为16的位置开始存储,是short类型大小2的倍数,所以可以直接存储2个字节,即16和17两个位置。

但是,根据上述规则3:结构体的总⼤⼩,也就是sizeof的结果,.必须是其内部最⼤
成员的整数倍.不⾜的要补⻬,此时结构体总大小为18,不是该结构体内部最大成员的整数倍,因此需要取比18大的最小的8的整数倍,也就是24.

扩展

老规矩,先附上图:


15996355351685.jpg

当结构体内部包含结构体成员的时候,计算方式略有不同(参考上述规则第二条),其中非结构体成员的计算规则不变。

  • 如上图所示,结构体之前的a、b、c存储到了第11位;
  • 根据上述规则2,结构体成员存储开始位置需要是该结构体内部成员的最大成员大小,当前例子中即为8的整数倍,因此,从16位开始存储,其中16-23位为struct1.a,24和25为struct1.b;
  • d的存储规则和之前一样,从32位开始,存储到35位。

最后,根据上述规则3:结构体的总⼤⼩,也就是sizeof的结果,.必须是其内部最⼤
成员的整数倍.不⾜的要补⻬,此时结构体总大小为35,不是该结构体内部最大成员的整数倍,因此需要取比35大的最小的8的整数倍,也就是40.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350