内存
计算机中内存是以字节为单位划分的,每一个内存地址 对应内存区的一个字节Byte,一个字节大小为8Bit,可以存放一个8位的二进制数(比如常见的Jpg图片颜色格式为RGB,每一个像素占三个字节分别存储R.G.B颜色,分别占用一个字节的空间,所以常用颜色值是0-255)
大小端模式
在ios中,自从5s开始手机的处理器全面变成64位,Int类型在编译器中占用64个bit,也就是8个字节,由于内存是以字节单位划分的,所以存储为多个字节的单一类型数据,因此产生了大小端模式
ios为小端模式
比如一个16进制的数据 0X12345678 低地址存78高地址存12这样为小端模式(可以记为电池负极在前)

大端模式相反 低地址存高位数据12,高地址存高位数据78
内存对齐
定义两个结构体,成员变量完全一样,顺序不同,占用空间大小却不一样
struct A{
let a:Bool = false // 1字节
var b:Int32 //4字节
var c:Bool = false //1字节
}
struct B{
var b:Int32 //4字节
let a:Bool = false //1字节
var c:Bool = false //1字节
}
var a = A.init(b: 0)
var b = B.init(b: 0)
MemoryLayout.stride(ofValue: a) //12
MemoryLayout.alignment(ofValue: a)//4
MemoryLayout.stride(ofValue: b)//8
MemoryLayout.alignment(ofValue: b)//4
stride为实际分配的内存空间
alignmengt为内存对齐大小
以结构体A来说,先分配了变量a 布尔类型所占空间一个字节,内存对齐方式为4,可以将4个字节看为一个整体,到变量b时,此时a所占用的一个整体,还剩7个字节无法存入变量b,所以又开辟 4个字节(对齐大小)存放b,然后又给c又占用一个字节,但是b所占的内存整体无法存储多余字节,所以又开辟一个4字节空间
结构体B 先存放Int类型的b,正好占用4个字节,然后又开辟四个字节的空间,这个空间可以同时存放a,和c两个变量,所以所占内存为8个字节
ios中内存对齐的大小是编译器决定的,在以上的结构体中,是以占用空间最大的成员变量的大小为对齐的大小
如果将Struct B中的Int32改为64,内存对齐大小就变为8,然后整体大小就变为8 + 8 16个字节
内存对齐是以牺牲内存空间来提高CPU的性能的空间换时间的策略
为什么要内存对齐
有的架构的cpu拒绝读取没有内存对齐的数据,是因为未对齐的数据会大大降低 CPU 的性能。
CPU 存取原理 (部分内容转字豆瓣菜)
程序员通常认为内存印象,由一个个的字节组成。

但是,你的 CPU 并不是以字节为单位存取数据的。CPU把内存当成是一块一块的,块的大小可以是2,4,8,16字节大小,因此CPU在读取内存时是一块一块进行读取的。每次内存存取都会产生一个固定的开销,减少内存存取次数将提升程序的性能。所以 CPU 一般会以 2/4/8/16/32 字节为单位来进行存取操作。我们将上述这些存取单位也就是块大小称为(memory access granularity)内存存取粒度。

为了说明内存对齐背后的原理,我们通过一个例子来说明从未地址与对齐地址读取数据的差异。这个例子很简单:在一个存取粒度为 4 字节的内存中,先从地址 0 读取 4 个字节到寄存器,然后从地址 1 读取 4 个字节到寄存器。
当从地址 0 开始读取数据时,是读取对齐地址的数据,直接通过一次读取就能完成。当从地址 1 读取数据时读取的是非对齐地址的数据。需要读取两次数据才能完成。

而且在读取完两次数据后,还要将 0-3 的数据向上偏移 1 字节,将 4-7 的数据向下偏移 3 字节。最后再将两块数据合并放入寄存器。

对一个内存未对齐的数据进行了这么多额外的操作,这对 CPU 的开销很大,大大降低了CPU性能。所以有些处理器才不情愿为你做这些工作。
网友评论