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 ( int
como 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
)。基本数据类型(int
、double
等)的大小与系统相关。结构体涉及字节对齐。
示例:
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.有如下结构体Struct1
和Struct2
分别占用多大内存?
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 a
Ocupa4
un byte, de[0~3]
.char b
Ocupa1
un byte,[4]
.short c
Ocupa2
un byte y debe2
alinearse con bytes, así que sáltelo5
[6~7]
S1
El todo nunca0~7
necesita ser llenado. bytes8
_
-
S2:
double a
bytes8
,[0~7]
.char b
bytes1
,[8]
.struct S1 s1
bytes8
_ Dado que elS1
elemento máximo interno esint a
así, debe4
alinearse, por lo que[12~19]
.bool c
bytes1
,[20]
.S2
El todo es de un0~21
total de21
bytes, que debe llenarse conS2
el elemento más grande en el medio.double a
Entonces debería ser24
bytes.
producción:
size :24
复制代码