iOSの基礎となる探索2:メモリの調整1

8月のアップデートチャレンジに参加して2日目です。イベントの詳細については、8月のアップデートチャレンジをご覧ください。

メモリアラインメントの原則

1.データメンバーの配置ルール

構造体(struct)または和集合(union)のデータメンバーの場合、最初のデータメンバーはオフセットが0の場所に配置され、後続の各データメンバーの開始位置は、メンバーのサイズまたはサブのサイズから格納されます。 -メンバーのメンバー(メンバーに配列、構造体などのサブメンバーがある場合)は、整数の倍数(int4バイトなど、4の整数倍から格納する必要があります)から始まります。

2.メンバーとしての構造

構造体にいくつかの構造体メンバーがある場合、構造体メンバーは、構造体の最大要素のサイズの整数倍から格納する必要があります。(structaにはstructbが含まれ、bにはchar、int、double、およびその他の要素が含まれます。その場合、bは8の整数倍から格納する必要があります)。

3.最初の仕事

sizeofの結果である構造体の合計サイズは、最大メンバーの整数倍でなければなりません。足りないものを補ってください。

プリミティブデータ型のメモリサイズ

C OC 32ビット 64ビット
ブール BOOL(64ビット) 1 1
署名された文字 (__signed char)int8_t、BOOL(32ビット) 1 1
unsigned char ブール値 1 1
短い int16_t 2 2
unsigned short ユニチャー 2 2
int、int32_t NSInteger(32ビット)、boolean_t(32ビット) 4 4
unsigned int boolean_t(64ビット)、NSUInteger(32ビット) 4 4
長いです NSInteger(64ビット) 4 8
unsigned long NSUInteger(64ビット) 4 8
長い長い int64_t 8 8
浮く CGFloat(32ビット) 4 4
ダブル CGFloat(64ビット) 8 8

メモリサイズを取得する方法

1. sizeof(expression-or-type)

sizeof()C/C++中的关键字,它是一个运算符,不是函数。作用是取得一个对象(数据类型或者数据对象)的长度(即占用内存的大小,以byte为单位,返回size_t)。基本数据类型(intdouble等)的大小与系统相关。结构体涉及字节对齐。

示例:

    struct Stu {

        char c;
        int i;
        double d;
    };

    void test() {

        //基本数据类型
        int age = 18;
        size_t sizeAge1 = sizeof(age);
        size_t sizeAge2 = sizeof age;
        size_t sizeAge3 = sizeof(int);
        NSLog(@"age size: %zu, %zu, %zu",sizeAge1,sizeAge2,sizeAge3);

        //结构体
        struct Stu s;
        s.c = 'c';
        s.i = 18;
        s.d = 180.0;

        size_t sizeS1 = sizeof(s);
        size_t sizeS2 = sizeof s;
        size_t sizeS3 = sizeof(struct Stu);
        NSLog(@"s size: %zu, %zu, %zu",sizeS1,sizeS2,sizeS3);

        //指针
        NSObject *obj = [NSObject alloc];
        size_t sizeObj1 = sizeof(obj);
        size_t sizeObj2 = sizeof obj;
        size_t sizeObj3 = sizeof(NSObject *);
        NSLog(@"obj size: %zu, %zu, %zu",sizeObj1,sizeObj2,sizeObj3);
    }

复制代码

输出:

age size: 4, 4, 4
s size: 16, 16, 16
obj size: 8, 8, 8
复制代码
  • 通过类型和实例都可以获取内存大小,这也说明开辟的内存大小在类型确定后就已经确定了。
  • sizeof是运算符不是函数。3种语法形式都可以,需要注意的是通过类型获取的方式必须在()中。

2. class_getInstanceSize

这个函数是rutime提供的获取类的实例锁占用的内存大小。大小至于成员变量有关。获取的是实际占用的空间(8字节对齐)。

3. malloc_size

malloc_size就是alloc中实际开辟的空间。

案例份分析

1.有如下结构体Struct1Struct2分别占用多大内存?

struct Struct1 {
    double a; // [0,7]
    char b;     // [8]
    int c;        // 根据第一准则要从4的倍数开始,所以[12,13,14,15]。跳过9,10,11
    short d;  //[16,17]
}struct1;
//根据第三准则总大小要是8的倍数,那就要分配24字节。

struct Struct2 {
    double a; //[0,7]
    int b;        //[8,11]
    char c;     //[12]
    short d;   //根据准则1跳过13,从14开始 [14,15]
}struct2;
//这里0~15大小本来就为16了,所以不需要补齐了。
复制代码

验证:

NSLog(@"struct1 size :%zu\nstruct2 size:%zu",sizeof(struct1),sizeof(struct2));
复制代码

输出:

struct1 size :24
struct2 size:16
复制代码
  • 结构体中数据类型顺序不一致占用的内存大小可能不一致。
  • 大小计算从0开始,Struct2并没有进行第三原则补齐。

2. 增加一个Struct3中有结构体嵌套,那么占用大小是多少?

struct Struct3 {
    double a;                  //[0,7]
    int b;                         //[8,11]
    char c;                     //[12]
    short d;                   //跳过13 [14,15]
    int e;                        // [16,19]
    struct Struct1 str; //根据准则2,Struct1最大元素为`double`类型,所以从24开始。根据`Struct1`分配的时候24个字节,所以str为[24,47]
}struct3;
//所以Struct3占用内存大小为48字节。
复制代码

验证:

NSLog(@"struct3 size :%zu",sizeof(struct3));

struct3 size :48
复制代码

在这里有个疑问,准则3是先作用在Struct1再作用Struct3还是最后直接作用在Struct3?不妨验证一下:

struct Struct4 {
    struct Struct1 str;
    char c;
}struct4;
复制代码

Struct1本身占用18字节,补齐后占用24字节。如果Struct4最终占用32字节那么就是第一种情况,张永24 字节则是第二种情况。

NSLog(@"struct4 size :%zu",sizeof(struct4));
struct4 size :32
复制代码

这也就验证了猜想,结构体嵌套从内部开始补齐。这也符合常理。

3. 修改结构体如下:

struct S1 {
    int a; // 4  [0,3]
    char b;// 1  [4]
    short c; // 2 [6,7]
}; // 0~7 8字节

struct S2 {
    double a; // 8 [0,7]
    char b;   // 1 [8]
    struct S1 s1; // 8  [12,19]  按s1自身中存的最大a的4字节的倍数对齐
    bool c; // 1 [20]
};
//0~20一共21个字节,按最大的8字节对齐。应该24字节。
复制代码
struct S2  s2;
NSLog(@"size :%zu",sizeof(s2));
复制代码

这个时候s2大小为多少?

分析:

  • S1:

    • int a4から1バイトを占有します[0~3]
    • char b1バイトを占有します[4]
    • short c1バイトを使用し、バイトに揃える2必要があるため、スキップしてください25 [6~7]
    • S1全体0~7を埋める必要はありません。バイト8
  • S2:

    • double aバイト8[0~7]
    • char bバイト1[8]
    • struct S1 s1バイト8S1内部の最大要素はそうなので位置合わせint aする必要があります4[12~19]
    • bool cバイト1[20]
    • S2全体は0~21合計21バイトからのものであり、中央S2の最大の要素でdouble a埋める必要があります。24したがって、バイトである必要があります。

出力:

size :24
复制代码

おすすめ

転載: juejin.im/post/6991776265837477895
おすすめ