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

为什么要内存对齐

  • 内存
  • 2024-05-18 11:44:55
  • 8682

一、结构体内存对齐1.什么是内存对齐?
2.为什么需要内存对齐?
3源代码内存对齐规则

计算机内存是以字节为单位划分的理论上,似乎对任何类型的变量的访问都可以从任何地址开始,但是现实的计算机系统有一个限制,基本数据类型可以存储在内存中,并且要求该数据的首地址值必须是某个数字k(通常是4或8的倍数,这就是称为内存对齐)。内存对齐是一种在计算机内存中排列数据(显示为变量地址)和访问数据(显示为CPU读取数据)的方法。
内存对齐包括两个独立但又相互关联的部分:基本数据对齐和结构数据对齐。

1.平台原因(传输原因):并不是所有的硬件平台都可以访问任意地址的任意数据,只能访问某个地址的某些类型的数据,否则会抛出硬件异常。
2.性能原因:数据结构(尤其是堆栈)应尽可能在自然边界上对齐。原因是为了访问未对齐的内存,处理器必须使两次并行的内存访问只需要一次访问;

当我们定义一个结构体时,它是如何存储在内存中的?占用多少字节的内存空间?

从打印输出可以看出问题结构体中的变量是一样的,只是顺序不同,导致这个结构体占用的内存大小影响了iOS

1。数据成员对齐规则:对于结构体(structural)(或联合体)数据成员,第一个数据成员放置在偏移0处,并且后续每个数据成员存储的起始位置必须从
的整数倍开始成员大小或成员子成员大小(只要成员有子成员,如数组、结构体等)(例如,如int为4字节,则从4的整数倍开始地址存储
min(当前起始位置m,n)m=9n=49101112
结构体作为成员:如果结构体中有特定的结构体成员,那么Storage结构体成员应该从以下地址开始:最大内部元素大小的整数倍(structa包含structb,b
包含char、int、double等元素,则b必须存储为的整数倍。)
3结构体的总大小,即大小的乘积,必须是所制作的<.br/>成员的最大整数倍

以上面两个结构体为例

最终结果大小为数据类型<所占空间的大小。br/>class_getInstanceSize获取类实例对象占用的内存大小
malloc_size获取系统实际分配的内存大小

>4<<4,其中右边shift4+leftshift4相当于把最后4位擦成0,后面跟k/16*16类似,是16字节对齐算法,如果小于16就变成0

对于对象来说,实际的对齐方式是8字节对齐,8字节对齐就足以满足对象的要求
为了避免一切容错,苹果系统使用16字节对齐内存,主要是因为当8字节对齐时使用对齐方式后,第二个内存——两个对象会彼此靠近,使其看起来更加紧凑,而16字节则相当宽松,有利于苹果未来的扩展。p>


二、内存对齐有什么用呢,请举个例子说明一下.CPU在操作内存时有一个合并的概念:
如果操作1字节数据,它可以在任意地址。如果操作2个字节的数据,如果起始地址是偶数地址,则一次可以取2个字。段,如果起始地址为奇数,则需要两次内存操作才能完成;如果操作4字节数据,最好从能被4整除的值开始地址,这样可以用32位内存操作指令完成。同样,8字节的起始位置最好是能被8整除的值,可以用64位内存操作指令完成。
也就是说,如果对齐的话,可以一次性完成。如果不对齐,可能会完成多次。编译程序时也有对齐处理。一般来说,结构和物体估计都会进行对齐处理(将结构或物体的起始位置设置在边界上)。这样,只要你能处理好结构中对象之间的关系,对齐,你的数据就可以快速操作了。
有时候你定义了一个结构体,使用了多个字节,但它们并不是8或4的倍数,但是当你检查内存时,你可以发现它们占用了8或4的倍数(多了几个字节)被使用),这就是原因。
补充回答:
例如32位机器有32条地址线和32条数据线。当取数时,CPU32根据地址线与存储器地址0-3对齐。CPU的32位数据线也是如此。在一个读周期中只能读取地址0-3的3个字节。如果您在地址3-4处读取数据,CPU会自动将其分解为两次数据读取操作,一次读取8位3单元数据,一次读取8位4单元数据。
一次操作只能完成起始地址为0、4、8...的32位数据操作。内存不支持从单元1开始的4字节读取。CPU和内存的数据线必须与数据相对应。就排队吧。
如果没有这样的限制,CPU和内存的生产成本会更高。而且CPU和内存的控制总线标准很早就已经规定好了。CPU的制造商生产了具有你的功能的CPU,但内存不支持它。新标准必须在某一年某月进行国际谈判。你的这个想法只能实现。