iOS内存对齐分析

什么是内存对齐?

  • 在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构、联合等)的数据单元。在结构中,编译器为结构的每个成员按其自然边界(alignment)分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。

为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐”. 比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除.

为什么要内存对齐?

  • 1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
  • 2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问

内存对齐原则

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

对象内存地址分析

在了解OC对象地址前我们首先看一下不同数据类型所占据的内存地址大小


不同数据类型内存地址大小

在了解不同数据类型所占的内存大小后我们首先来看一下一个OC对象的内存地址情况,我们生命一个对象,它有如下属性

@interface SYPerson : NSObject

@property (nonatomic,copy) NSString *name;
@property (nonatomic,copy) NSString *sex;
@property (nonatomic) int age;
@property (nonatomic) int height;

@end

调用,给属性赋值并打印person对象的内存大小

    SYPerson *person = [[SYPerson alloc]init];
    person.name = @"Syong";
    person.sex = @"man";
    person.age = 17;
    
    NSLog(@"%@",person);
    NSLog(@"person对象实际需要的内存大小: %zd", class_getInstanceSize([person class]));
    NSLog(@"person对象实际分配的内存大小: %zd", malloc_size((__bridge const void *)(person)));

打印结果

打印结果

我们发现person对象内存大小一共分配了48字节,实际使用了40字节,那么这些内存地址到底是如何排列的呢?根据内存对齐的规则,我们得到下图所示的排列情况:
内存地址排列情况

  • 首先Person作为一个NSObject对象,本身的isa占有8字节,首地址从0开始排,那么地址情况就是[0,1,2,3,4,5,6,7]
  • 后面的数据成员存储首地址根据起始位置的isa大小的整数倍来排列,那么就是从8开始排,name作为NSString类型占8字节,即[8,9,10,11,12,13,14,15],同理后面的sex为[16,17,18,19,20,21,22,23]
  • age作为Int类型占有4字节,那么就是[24,25,26,27]
  • height作为long类型占有8字节,但是要从8的整数倍开始,27过后就是32是8的整数倍,那么就是从32开始排[32,33,34,35,36,37,38,39]
  • 到这里为止person对象所有占有的内存大小是40,而person对象总大小必须是内部最大成员的整数倍,也就是8的整数倍即40

那么这就出现了一个问题,为什么明明内存实际使用了40,从前面推算分配的内存也应该是40,但是为什么最后分配的内存结果确实48呢?

具体原因是Apple系统中的malloc函数分配内存空间时,内存是根据一个bucket的大小来分配的。bucket的大小是16,32,48,64,80 ...,可以看出系统是按16的倍数来分配对象的内存大小的

我们可以将person对象的所有属性注释,然后再打印person对象的内存大小来验证这个原因是否正确,得到下面结果:

无成员变量的`person`内存大小

或者我们只保留name和age两个属性再打印结果:
只保留name和age

这也验证了前面说法,虽然没有任何属性的person只有isa占据了8字节,但是分配了16字节;保留nameageperson实际使用24字节却分配了32字节。所以虽然前面内存只使用了40,按理说也应该分配40字节,但是因为系统按照最小16字节的bucket分配内存,那么根据内存对齐,补位就应该是分配48
通过前面的论证也证实了字节对齐的规则,其实我们也可以简化一下,对象本身就是结构体,也可以通过结构体来进行验证,这里我就不再使用结构体来复述一遍了,下面我们只看一种情况,那就是结构中嵌套结构体的时候,内存对齐是什么一个情况。

嵌套结构体的内存对齐

比如有这么两个结构体

#import <Foundation/Foundation.h>

struct SYStruct {
    int a;
    double b;
}struct1;

struct LGStruct {
    char a;
    int b;
    struct SYStruct c;
}struct2;

int main(int argc, const char * argv[]) {
    @autoreleasepool {
      NSLog(@"%lu-%lu",sizeof(struct1),sizeof(struct2));
    }
    return 0;
}
//输出结果:
//2020-09-08 23:42:03.207571+0800 001-内存对齐原则[12425:218745] 16-24
  • 结构体struct1里面有4字节int和8字节的doubule,a内存排列情况为[0,1,2,3],b从8的整数倍开始则为[8,9,10,11,12,13,14,15],那么一共是16个字节,满足最大成员double类型8的整数倍
  • 结构体struct2的a地址为[0],b[4,5,6,7],c作为一个结构体,其本身最大的成员大小为double类型的8,那么c为[8,9,10,11,12,13,14,15],根据结构体总大小必须是内部成员大小的整数倍,那么可得结构体struct2的大小应该为24。

总结

以上就是对内存对齐的一些分析,简单来说通过内存对齐可以达到更快的读取以及通过预留空间在读取数据时更加安全,通过牺牲一点内存的大小达到更快更强的目的。

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