【iOS】内存对齐

内存对齐

OC基本数据类型所占字节数对比

注1BOOL在32位机器被定义为char、在64位机器被定义为bool
boolean_t在32位机器被定义为unsigned int、在64位机器被定义为int
NSInteger在32位机器被定义为int、在64位机器被定义为long
NSUInteger在32位机器被定义为unsigned int、在64位机器被定义为unsigned long
CGFloat在32位机器被定义为float、在64位机器被定义为double

以上多变的情况是是使用宏定义实现的,编译后可查看其实现

注2:由于C语言只会将bool的非0值置为1,因此,BOOL的使用过程中应注意在32位机器上并非只有1和0两种可能取值,取值范围是-128~127(其实也不用太在意,因为现在几乎没几个人还在用32位的手机)

内存对齐规则

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

先有下面三个结构体:

objectivec 复制代码
struct Struct1 {
    double a;  // 8
    char b;    // 1
    int c;     // 4
    short d;   // 2
} struct1;

struct Struct2 {
    double a;  // 8
    int b;     // 4
    char c;    // 1
    short d;   // 2
} struct2;

struct Struct3 {
    double a;  // 8
    int b;     // 4
    char c;    // 1
    short d;   // 2
    int e;     // 4
    struct Struct1 struc;  // 24
} struct3;

根据上面的内存对齐规则,可计算出struct1所占用的字节数是24,struct2所占用的字节数是16,struct3所占用的字节数是48,通过sizeof也可以验证这些答案

内存对齐原因

性能

内存是以字节为基本单位,cpu在存取数据时,是以块为单位存取,并不是以字节为单位存取。频繁存取未对齐的数据(存取未对齐的数据可能开始在上一个内存块,结束在另一个内存块,中间可能要经过复杂运算在合并在一起,降低了效率 ),会极大降低cpu的性能。字节对齐后,会减低cpu的存取次数,提高了cpu的访问速率,这种以空间换时间的做法目的降低cpu的开销

跨平台

有些硬件平台并不能访问任意地址上的任意数据的,只能处理特定类型的数据,否则会导致硬件层级的错误。

有些CPU(如基于 Alpha,IA-64,MIPS,和 SuperH 体系的)拒绝读取未对齐数据。当一个程序要求这些 CPU 读取未对齐数据时,这时 CPU 会进入异常处理状态并且通知程序不能继续执行。

举个例子,在 ARM,MIPS,和 SH 硬件平台上,当操作系统被要求存取一个未对齐数据时会默认给应用程序抛出硬件异常。所以,如果编译器不进行内存对齐,那在很多平台的上的开发将难以进行。

OC对象内存对齐

在之前的文章中已经了解到OC对象实际上是结构体,结构体成员变量的内存排序遵循内存对齐规则,那么对象属性的内存排序也遵守内存对齐规则

创建一个Person类:

objectivec 复制代码
@interface Person : NSObject

@property (nonatomic, assign)double a;
@property (nonatomic, assign)char b;
@property (nonatomic, assign)int c;
@property (nonatomic, assign)short d;

@end

Person* person = [[Person alloc] init];
person.a = 7.7;
person.b = 's';
person.c = 7;
person.d = 7;
NSLog(@"%zd %zd", class_getInstanceSize([Person class]), malloc_size((__bridge const void *)(person)));  //  24 32

通过输出我们可以看出成员变量所占内存大小是24字节,其中isa要占8个字节,其余成员占16个字节,所以至少需要24字节

操作系统在分配内存时,也会有"内存对齐",所以size是24,malloc_size返回 32,即系统实际分配内存32字节(从内存对齐的角度也可以算出32)

总结

内存对齐可以提高cpu的存取效率同时提升安全性,会有部分内存的浪费,但是系统又会根据数据存储情况进行内存优化,尽可能降低内存浪费,这样即保证了性能又减少了浪费

相关推荐
二流小码农5 小时前
鸿蒙开发:异步并发操作
android·ios·harmonyos
MavenTalk8 小时前
前端技术选型之uniapp
android·前端·flutter·ios·uni-app·前端开发
豪冷啊10 小时前
iOS 17.4 Not Installed
ios
Topstip10 小时前
iOS 19 重大更新泄露,将带来更“聪明”的 Siri 挑战 ChatGPT
人工智能·ios·ai·chatgpt
软件聚导航2 天前
uniapp 安卓和ios震动方法,支持息屏和后台震动,ios和安卓均通过测试
android·ios·uni-app
键盘敲没电2 天前
【iOS】知乎日报总结
学习·ios·objective-c·xcode
安和昂2 天前
【iOS】UICollectionView的学习
学习·ios·cocoa
二流小码农3 天前
鸿蒙开发:自定义一个任意位置弹出的Dialog
android·ios·harmonyos
小江村儿的文杰3 天前
UE4 iOS Package的过程与XCode工程中没有游戏Content的原因
macos·ios·ue4·xcode
__WanG3 天前
Flutter将应用打包发布到App Store
前端·flutter·ios