当前位置:首页 > 内存 > 正文

内存对齐的目的(内存对齐的目的和原理)

  • 内存
  • 2024-05-15 12:58:57
  • 8964

一、内存对齐原理

对于程序来说,如果变量的数据存储范围在寻址步长范围内,则可以通过一次寻址读取该变量的值。如果数据存储范围超出步长范围,则需要读取该步长。寻址两次然后合并数据,这大大降低了效率。例如,double数据在内存中占用8个字节。如果地址是8,那么就很容易管理。如果是20,则需要两次寻址。这会产生数据对齐规则,其中涉及在单个步骤中存储尽可能多的数据并避免步骤之间的存储。这就是内存对齐。32位编译环境中默认对齐为4字节,64位编译环境中默认对齐为8字节。

现代处理器通常具有多层缓存。处理器访问这些缓存中的数据的效率远高于访问内存中的数据(就像处理器访问内存中的数据一样)。比访问磁盘上的数据更有效)。
如上所述,一般来说,CPU总是以字大小(在32处理器上通常为4字节)来访问数据,因此如果数据在内存中没有对齐,那么当CPU访问该数据时,可能会出现错误。需要执行更多的读取操作。在这样的机器上,读取2个字节的数据往往比读取4个字节的数据慢得多。

改进的访问范围
对于给定的地址空间,如果架构可以确定2LSB始终为0(如32位机器),那么它可以访问4倍以上的内存(2位可以代表4种不同的状态)。从地址中删除2个LSB会导致4字节内存对齐或“跨步”,因为地址每次增加1时,实际上会增加bit2,而不是bit0。(因为低2位始终为00)
这甚至会影响系统的物理设计:如果地址总线需要少2位,则处理器上可能会少2个引脚。

前面说过,CPU每次访问数据的宽度是一个字。如果C语言程序数据在内存中总是对齐的,那么CPU对数据的访问总是原子的,就是这种情况。对于许多无锁数据来说都是一个问题。结构和其他竞争要求的正确运作至关重要。

规则:
1。数据成员对齐规则:对于结构体(或联合)的数据成员,第一个数据成员放置在偏移量0处,后续的每个数据成员放置在偏移量0处。每个数据成员根据指定值中的较小者进行对齐由#pragmapack和数据成员本身的长度。
2.结构(或联合)的整体对齐规则:一旦数据成员完成了各自的对齐,结构(或联合)本身也必须对齐。对齐方式将基于#指定的值。pragmapack和最大(或联合)结构使用最短的数据成员长度。
3.结合1和2,我们可以推断:当#pragmapack的n值等于或大于所有数据成员的长度时,n值的大小将不起作用。

#pragmapack实际上指定了内存对齐系数,如1,2,4,8,16。默认的xcode对齐系数是8。

查找内存的大小(以字节为单位)下面两个结构体

打印结果

分析如下
第一个demoStruct1,起始偏移量为0
a,类型int,4字节,<8,按4对齐,存储位置为[0,3]
b,int类型,4字节,<8,按4对齐,存储位置为[4,7]
c,char类型,1byte,<8,按1对齐,存储位置为[8,8]
d,double类型,8字节,=8,按8对齐,当前位置不够,填写[9,15]首先,然后存储,存储位置为[16,23]
e[7],字符数组类型,7个字符字节,<8,按1对齐,存储位置为[24,30]
最后填写8的整数倍,即[31,31]
完成:使用位置为[0,31],占用字节数为32

重新解析demoStruct2,起始偏移量为0
a,int类型,4字节,<8,按4对齐,存储位置为[0,3]
b,int类型,4字节,<8,按4对齐,存储位置为[4,7]
c,类型char,1个字Section,<8,按1对齐,存储位置为[8,8]
e[7],字符数组类型,7个字节的字符,<8,按1对齐,存储位置为[9,15]
d,double类型,8个字节,=8,按8对齐,存储位置为[16,23]
完整:使用位置为[0.23],占用字节数为24

适当调整变量类型或位置有助于提高内存使用率


二、结构体内存对齐

1什么是内存对齐?
为什么需要内存对齐?
3>计算机内存是以字节为单位划分的,理论上来说,访问任何类型的变量都可以从任意开始地址,但是当前的计算机系统对基本数据类型可以存储的位置有限制。要求该数据的首地址是某个数字k(通常是4或8的倍数,这就是所谓的内存对齐)。内存对齐是一种在计算机内存中排列数据(显示为变量的地址)和访问数据(显示为CPU读取的数据)的方法。
内存对齐包括两个独立但相关的部分:基本数据对齐和结构数据对齐。

1平台原因(移植原因):并不是所有的硬件平台都可以访问任意地址的任意数据,否则会出现硬件异常。
2性能原因:数据结构(尤其是堆栈)应尽可能在自然边界上对齐。原因是,要访问非对齐内存,处理器必须对对齐内存进行两次访问,而对对齐内存只需要一次访问。

当我们定义了一个结构体后,它是如何存储在内存中的呢?需要多少字节的内存空间?

从打印结果中我们可以看出iOS存在问题

1.数据成员对齐规则:对于结构体(或联合)的数据成员,第一个数据成员设置为偏移量0以及后续每个数据成员存储的起始位置。必须
从成员大小或成员子成员大小的整数倍开始(只要成员有子成员,例如数组、结构体等)(例如,如果int是4字节则从4的整数倍开始存储的地址开始
min(当前起始位置m,n)m=9n=49101112
2结构体作为成员:如果有某些结构体成员在结构体中,那么Storage结构体的成员必须从最大元素大小的整数倍的地址开始(structa包含structb,b
包含char、int、double等元素,则b必须存储为8的整数倍。
成员任何不足都必须补足

以上两个结构体为例

最终的大小结果就是大小。
class_getInstanceSize获取类实例对象占用的内存大小
malloc_size获取系统分配的内存大小

>4<<4,其中右移4+左移4相当于将最后4位擦除为零,后面跟k/16*16一样,是16字节对齐算法,如果小于超过16,就变成0

对于一个对象来说,它真正的extent是8字节的extent,8字节的extent足以满足对象的需求
为了防止一切容错,Apple系统使用16字节对齐的内存,主要是因为当使用8字节对齐时,两个对象的内存会彼此靠近,使其显得更加紧凑,而16字节则相对便宜,有利于Apple未来的扩展/p>


三、谁能给我详细解释下内存对齐啊?我能明白一点,哪位大神帮帮忙。内存上有一个凹口。根据版本的不同,缺口的位置也不同,对应内存位置上的一个分区。例如之前的sdrom内存有2个空间,对应的sdrom内存位置有2个分区;ddr1内存有1个空间,ddr1插槽有1个分区。你如何决定?首先确定你的主板型号,看看主板支持什么类型的内存,购买对应的内存,然后将内存槽口对准内存插槽分区,插上,就可以了。内存上的凹口旨在防止反向插入。
另外,如果你问的是C语言中的内存对齐,这里还有另一个答案:
为什么要有内存对齐?
以下内容摘自《Intel32位架构手册》。
单词、双字和四字不需要在内存中与自然边界对齐。(对于字、双字和四字,自然限制分别是偶数地址、可被4整除的地址和可被8整除的地址。)
在所有情况下,为了提高程序的性能,数据结构(特别是烟囱)应尽可能与自然边界对齐。原因是为了访问未对齐的内存,处理器必须执行两次内存访问。然而,访问对齐内存只需要一次访问。
跨越4字节边界的字或双字操作数,或跨越8字节边界的四字操作数被视为未对齐,需要两个总线周期来访问内存。从奇数地址开始但不跨越字边界的字被认为是对齐的,并且可以在单个总线周期中访问。
一些对双四字进行操作的指令要求内存操作数与自然边界对齐。如果操作数未对齐,这些指令将生成一般保护异常(#GP)。双四字的自然限制是可被16整除的地址。对双四字进行操作的其他指令允许未对齐访问(不会生成一般保护异常),但需要额外的内存总线周期来访问内存中的未对齐数据。