不同数据类型占用字节图
内存对齐的原则
1、数据成员对齐规则: 结构(struct
)(或联合(union
)的)数据成员,第一个数据成员放在 offset
为0
的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说数组,结构体等)的整数倍开始(如int为4字节,要从4的整数倍地址开始存储)
2、结构体作为成员: 如果一个结构体有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a 里存有struct b, b里有 char, int ,double等元素,那b 应该从8的整数倍开始存储。)
3、收尾工作:结构体的总大小,也就是sizeof的结果,必须是内部最大成员的整数倍,不足要补齐
iOS获取内存大小的三种方式
sizeof
: 是C/C++中的一个操作符(operator),简单的说其作用就是返回一个对象或者类型所占的内存字节数。在编译阶段 就会确定大小
class_getInstanceSize
: 这个方法由runtime提供api,用于获取实例对象所占的内存大小,本质是获取实例对象中成员变量的内存大小
(注
:如自定义类或继承关系 属性的多少变化而变化,如单纯的继承NSObject并且没有任何属性 打印为8 因为 有隐藏 isa 万物皆对象,而对象的本质为 继承 objc_object 的结构体 它就是对象模板)
malloc_size
: 获取系统实际分配的内存大小(16字节对齐
)
拓
: 我们知道alloc 流程 最重要的三部曲
cls->instanceSize:计算需要开辟的内存空间大小(这里有一个算法为16字节对齐)
calloc:申请内存,返回地址指针
obj->initInstanceIsa:将 类 与 isa 关联
结构体内存对齐
首先创建 3个结构体 这三个结构体内部参数类型 都一样 只不过 是顺序不一样
[图片上传中...(截屏2020-09-15下午2.17.31.png-4046a7-1600150682775-0)]
{
char a; //1
double b;//8
int c; //4
short d; //2
}Mystruct1;
struct Mystruct2{
double b;//8
char a; //1
int c; //4
short d; //2
}Mystruct2;
struct Mystruct3{
char a; //1
short d; //2
int c; //4
double b;//8
}Mystruct3;
根据内存规则 我们画图来分析
分析: ofsize 0
开始 存储char
类型占一个
字节的a
; b
要存储了 首先分析自己自身多大
我是double
类型的 我需要占8
个字节 可是 如果从 a
后面 开始 不满足自身 8 的倍数
的地方 那我只能往下数 看来只能到 8的位置开始 容纳我的身体 【8 - 15 】
; 该c
出厂 存储了 我自身占用 4字节
我是int
类型的 我只能先从16 开始 我的天 真幸运 正好符合我自身4字节的倍数
我可以 存储了 【16- 19】
d
出场了 我自身占 2个字节
得需要从20 位开始找能不能满足 我的倍数的规则要求
20 除 2 可以的 我也可以放下了 【20 - 21】
Mystruct1 结构体
承载了 21+1 个字节
突然 大喇叭喊出规则:结构体的总大小
,也就是sizeof的结果,必须是内部最大成员的整数倍,不足要补齐
:好的 那我里面最大的是 8 字节 那么 我现在 算出来 22 那么 补齐就好了嘛 不要激动 心里默念: 二 八 16, 不满足 ; 三八 24 满足啦 结束了。所以 Mystruct1 占用 24个字节空间
分析: 从 0 的位置开始存 自身是double 类型的占用8个字节的 b【0-7】
a 是 占用一个字节的char类型 ,从 8的位置 满足自身1字节的倍数 所以 存储在8的位置【8】,c来了 首先 我自己是 int类型 我占用 4个字节 我只能从 9的位置开始存 可是 不满足 规则 必须是自己字节数的倍数,那我只能往下数了 9.10.11.12 咦!12是我的位置 那就从12开始【12-15】, d来了 首先想自己是 short类型的占用2个字节 我只能先从 16 的位置看 咦!这么巧 正好符合规则 是我的倍数 存这没毛病
Mystruct2 结构体
承载了 17+1 个字节
,大喇叭又开始广播了:结构体的总大小
,也就是sizeof的结果,必须是内部最大成员的整数倍,不足要补齐
,好的村长 我补齐: 结构体最大的是 double占 用8个字节 我算出来18。 2*8 = 16 不满足 3 *8 = 24 村长 我满足了。所以 Mystruct2 占用 24个字节空间
分析:从0 开始 存入一个 char类型的a d 来了 首先分析自己 是short类型 占用2个字节 那我如果从1 开始 那不是我的倍数 不满足规则。所以 往下看 2 好像 是我字节的倍数 ,好的存入 【2-3】 c来了我是 int类型的 占4字节 我只能从4开始存储 好像也满足 是我的自身4字节的倍数 ,好的存入【4-7】,b来了 嗯我是double类型 我自身占用8字节 我只能从 8号位置 开始存储 好像 8也是我的倍数 好的 存入【8-15】
`Mystruct3 结构体 承载了 15+1个字节,行了大喇叭别广播了 我知道了 我内部成员最大 的为8字节 必须是 8字节的整数倍 不足要补齐。
2*8 = 16 我满足了 ,所以 Mystruct3占用 16个字节
嵌套结构体
我们已经对结构体内存很明晰了 那么来个嵌套的
struct Mystruct3{
char a; //1 0
short d; //2 [2 3]
int c; //4 [4 5 6 7]
double b;//8 [8 9 10 11 12 13 14 15]
}Mystruct3;
struct Mystruct4{
char a; //1
int b; //4
struct Mystruct3 struct3; //16
}Mystruct4;
上面我们分析了 Mystruct3 占用 16 个字节 那么 Mystruct4占用多少呢
分析:
a 是占用一个字节的char类型 放在【0】
b是 占4字节的int类型 找到最近的 自身的占用字节的倍数的位置 为【4-7】
sturct3 是一个占用 16字节 的结构体 我们首先分析它最大的成员占多少内存 这里 为double 类型 占8个字节 所以应该 从8 的倍数开始存放第一个元素 上面的b占了【4-7】故只能从8往后数 正好8的位置 是 sturct3里最大元素的倍数 故第一个元素位置为【8】第二个元素为short类型占2个字节 所以需要从8 往后数正好满足自身的倍数 也就是【10 11】 第三个元素为double类型 占8个字节 所以需要从11 往后数满足8 的倍数 也就是【16 - 23】 因为 sturct3 是个结构体 也满足内存对齐原则 也就是 最大元素的倍数 sturct3占了 16字节 正好满足 对齐原则 a 占1 个 空白占3 b 占4 个 加在一起占 24个
sturct4 内存对齐 为 最大成员的倍数 最大成员 为struct3 里double 8 字节 所以
又是大喇叭所说的 内部成员最大字节 的倍数
所以 sizeof(Mysturct4) 最终 为 24
注意:
- 嵌套结构体 ,最大成员 不是 被嵌套的结构体本身大小 ,而是要看被嵌套的结构体元素 和当前结构体元素 谁大 谁最大就是谁的倍数
- 被嵌套的结构体 第一个元素占用位置 由 自身最大元素字节的倍数开始