Exploración subyacente de iOS 2: alineación de memoria 1

Este es el segundo día de mi participación en el Desafío de actualización de agosto. Para obtener detalles del evento, consulte: Desafío de actualización de agosto

principios de alineación de la memoria

1. Reglas de alineación de miembros de datos

Para los miembros de datos de una estructura ( struct) o una unión ( union), el primer miembro de datos se coloca donde el desplazamiento es 0, y la posición inicial de cada miembro de datos subsiguiente se almacena a partir del tamaño del miembro o el tamaño del sub -miembro del miembro (siempre que el miembro tenga submiembros, como matrices, estructuras, etc.) a partir de un múltiplo entero ( intcomo 4 bytes, debe almacenarse a partir de un múltiplo entero de 4).

2. Estructura como miembro

Si hay algunos miembros de estructura en una estructura, los miembros de estructura deben almacenarse a partir de un múltiplo entero del tamaño del elemento más grande de la estructura. (struct a contiene struct b, b contiene char, int, double y otros elementos, luego b debe almacenarse a partir de un múltiplo entero de 8).

3. Primer trabajo

El tamaño total de la estructura, que es el resultado de sizeof, debe ser un múltiplo entero de su miembro más grande. Compensa lo que no es suficiente.

Tamaño de memoria de tipos de datos primitivos

C jefe 32 bits 64 bits
bool BOOL (64 bits) 1 1
carácter firmado (__caracter firmado) int8_t, BOOL (32 bits) 1 1
carácter sin firmar booleano 1 1
corto int16_t 2 2
corto sin firmar unicar 2 2
int 、 int32_t NSInteger (32 bits), boolean_t (32 bits) 4 4
int sin firmar boolean_t (64 bits), NSUInteger (32 bits) 4 4
largo NSInteger (64 bits) 4 8
largo sin firmar NSUInteger (64 bits) 4 8
largo largo int64_t 8 8
flotar CGFloat (32 bits) 4 4
doble CGFloat (64 bits) 8 8

Cómo obtener el tamaño de la memoria

1. sizeof(expresión-o-tipo)

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 aOcupa 4un byte, de [0~3].
    • char bOcupa 1un byte, [4].
    • short cOcupa 2un byte y debe 2alinearse con bytes, así que sáltelo5 [6~7]
    • S1El todo nunca 0~7necesita ser llenado. bytes 8_
  • S2:

    • double abytes 8, [0~7].
    • char bbytes 1, [8].
    • struct S1 s1bytes 8_ Dado que el S1elemento máximo interno es int aasí, debe 4alinearse, por lo que [12~19].
    • bool cbytes 1, [20].
    • S2El todo es de un 0~21total de 21bytes, que debe llenarse con S2el elemento más grande en el medio. double aEntonces debería ser 24bytes.

producción:

size :24
复制代码

Supongo que te gusta

Origin juejin.im/post/6991776265837477895
Recomendado
Clasificación