美文网首页iOS
[iOS] 内存对齐

[iOS] 内存对齐

作者: 沉江小鱼 | 来源:发表于2020-12-28 23:53 被阅读0次

1. 获取内存大小的三种方式

  • sizeof
  • class_getInstanceSize
  • malloc_size
1.1 sizeof
  • sizeof 是一个操作符,不是函数
  • 一般使用时,传入的对象是数据类型,这个在编译时决定
  • sizeof 最终得到的结果是该数据类型占用空间的大小
1.2 class_getInstanceSize
  • runtime提供的 api,用于获取类的实例对象所占用的内存大小
  • 返回具体的字节数,其本质是获取实例对象中成员变量的内存大小
1.3 malloc_size
  • 获取系统实际分配的内存大小
1.4 代码验证

可以通过代码进行验证:

#import <objc/runtime.h>

#import <malloc/malloc.h>

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];

    
    NSObject *object = [[NSObject alloc] init];
    NSLog(@"%lu",sizeof(object));
    NSLog(@"%lu",class_getInstanceSize([object class]));
    NSLog(@"%lu",malloc_size((__bridge const void *)(object)));
}

@end

输出结果:

2020-12-23 21:23:17.335020+0800 Test[3610:219003] 8
2020-12-23 21:23:17.335198+0800 Test[3610:219003] 8
2020-12-23 21:23:17.335440+0800 Test[3610:219003] 16
1.5 总结
  • sizeof

计算类型占用内存大小,其中可以放基本数据类型、对象、指针
对于对象而言,打印的就是对象 objc 的指针大小,所以是 8
对于指针而言,64 位下是 8 个字节

  • class_getInstanceSize

计算对象实际占用的内存大小,这个跟类的属性相关,如果类中没有自定义属性,仅继承于 NSObject,则类的实例对象实际占用的内存大小是 8,可以简单理解为 8 字节对齐

  • malloc_size

计算系统为对象实际分配的内存,可以看出实际分配的和实际占用的并不相等

2. 结构体内存对齐

下面,我们首先定义两个结构体,分别计算他们的内存大小,以此来引入今天的整体:内存对齐原理。

//1、定义两个结构体
struct Mystruct1{
    char a;     //1字节
    double b;   //8字节
    int c;      //4字节
    short d;    //2字节
}Mystruct1;

struct Mystruct2{
    double b;   //8字节
    int c;      //4字节
    short d;    //2字节
    char a;     //1字节
}Mystruct2;

//计算 结构体占用的内存大小
NSLog(@"%lu-%lu",sizeof(Mystruct1),sizeof(Mystruct2));

下面是输出结果:


image.png

两个结构体只有成员变量的顺序有所区别,但是在输出结果中,他们所占用的内存大小却是不相等的,这就是内存对齐现象。

2.1 内存对齐规则

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。在iOS中,Xcode默认为#pragma pack(8),即8字节对齐。

一般内存对齐的原则主要有3点,可以回看iOS-底层原理 02:alloc & init 源码学习中的说明。

内存对齐规则可以这么理解:

【一】 数据成员的对齐规则可以理解为min(m, n) 的公式, 其中 m表示当前成员的开始位置, n表示当前成员所需要的位数。如果满足条件 m 整除 n (即 m % n == 0), n 从 m 位置开始存储, 反之继续检查 m+1 能否整除 n, 直到可以整除, 从而就确定了当前成员的开始位置。
【二】数据成员为结构体:当结构体嵌套了结构体时,作为数据成员的结构体的自身长度作为外部结构体的最大成员的内存大小,比如结构体a嵌套结构体b,b中有char、int、double等,则b的自身长度为8
【三】最后结构体的内存大小必须是结构体中最大成员内存大小的整数倍,不足的需要补齐。

2.2 验证对齐规则

下表是各种数据类型在iOS中的占用内存大小,根据对应类型来计算结构体中内存大小:


image.jpeg

我们可以通过下图图来说明下为什么两个结构体MyStruct1 & MyStruct2的内存大小打印不一致的情况,如图所示:

image.png

结构体 MyStruct1 内存大小计算过程:

  • 变量 a:占 1 个字节,从 0 开始,此时min(0,1),即 0 存储 a
  • 变量b:占8个字节,从1开始,此时min(1,8),1不能整除8,继续往后移动,知道min(8,8),从8开始,即 8-15 存储 b
  • 变量c:占4个字节,从16开始,此时min(16,4),16可以整除4,即 16-19 存储 c
  • 变量d:占2个字节,从20开始,此时min(20, 2),20可以整除2,即20-21 存储 d

因此MyStruct1的需要的内存大小为22字节,而MyStruct1中最大变量的字节数为8,所以MyStruct1 实际的内存大小必须是8 的整数倍18向上取整到24,主要是因为24是8的整数倍,所以 sizeof(MyStruct1) 的结果是24

结构体MyStruct2 内存大小计算:

  • 变量b:占8个字节,从0开始,此时min(0,8),即 0-7 存储 b
    -变量c:占4个字节,从8开始,此时min(8,4),8可以整除4,即 8-11 存储 c
    -变量d:占2个字节,从12开始,此时min(12, 2),12可以整除2,即12-13 存储 d
    -变量a:占1个字节,从14开始,此时min(14,1),即 14 存储 a

因此MyStruct2的需要的内存大小为 15字节,而MyStruct1中最大变量的字节数为8,所以MyStruct2 实际的内存大小必须是8 的整数倍15向上取整到16,主要是因为16是8的整数倍,所以 sizeof(MyStruct2) 的结果是 16

相关文章

  • iOS内存对齐

    这篇文章我们来探索一下iOS内存对齐的原理,在探索完内存对齐原理之后,你就会明白内存对齐的好处。 在讲述内存对齐时...

  • iOS底层探究 - 内存对齐

    目录1:内存对齐的原因2:内存对齐的规则3:结构体内存分配演练以及在iOS中对象成员的内存分配探索 一 :内存对齐...

  • iOS底层之内存对齐算法解析

    目前但凡一个iOS岗面试都会问个内存对齐问题,那么什么是字节对齐?成员变量对齐和对象内存对齐有什么区别?今天我来为...

  • iOS 内存对齐

    在上一边文章中,我们在简单介绍内存对齐,今天我们更加深入一点: 一、获取内存大小的三种方式 先看下面这段代码: 看...

  • iOS - 内存对齐

    1、内存对齐是什么? 在计算机中,内存大小的基本单位是字节,理论上来讲,可以从任意地址访问某种基本数据类型。 但是...

  • iOS 内存对齐

    前言 现代计算机中内存空间都是按照 byte 划分的,从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但是...

  • iOS 内存对齐

    1. 对象内存对齐 在我们进行alloc一个对象的时候,通过源码[https://www.jianshu.com/...

  • iOS 内存对齐

    1.二进制重排 2.内存优化 3.sizeof 编译时获取类型所占内存的大小;class_getInstanceS...

  • iOS 内存对齐

    一、结构体内存对齐 1.1 结构体内存对齐三大原则 数据成员对⻬规则结构体(struct)或联合体(union)的...

  • [iOS] 内存对齐

    1. 获取内存大小的三种方式 sizeof class_getInstanceSize malloc_size 1...

网友评论

    本文标题:[iOS] 内存对齐

    本文链接:https://www.haomeiwen.com/subject/prgunktx.html