所以架构并不重要,除了 x86 传统上不会直接告诉你 mips 和 arm 传统上在哪里生成数据中止,而不是试图让它工作。
无关紧要的是所有处理器都有固定数量的引脚固定大小(最大)数据总线固定大小(最大)地址总线,“现代处理器”往往具有超过 8 位宽的数据总线,但地址上的单元仍然是一个 8 位字节,因此存在未对齐的机会。如果架构允许,在特定传输中大于一个字节的任何内容都有可能不对齐。
传输通常以某些字节和/或总线宽度为单位。例如,在 ARM amba/axi 总线上,长度字段以总线宽度、32 或 64 位、4 或 8 字节为单位。不,它不会以 4Kbytes 为单位......
(是的,这是基本的,我假设您了解所有这些)。
无论是 16 位还是 128 位,未对齐的惩罚来自额外的总线周期,如今每个额外的总线时钟。因此,对于 ARM 16 位未对齐传输(哪个 arm 将在其较新的内核上支持而不会出现故障),这意味着您需要读取 128 位而不是 64 位,64 位以获得 16 位不是惩罚,因为 64 位是总线的最小尺寸转移。每次传输,无论是数据总线的单个宽度还是多个数据总线都有多个与之相关的时钟周期,假设有 6 个时钟周期来执行对齐的 16 位读取,那么理想情况下,执行未对齐的 16 位需要 7 个周期。看起来很小,但它确实加起来。
缓存有很大帮助,因为缓存的 dram 端将设置为使用总线宽度的倍数,并且将始终对缓存提取和驱逐进行对齐访问。非缓存访问将遵循同样的痛苦,除了 dram 端不是几个时钟而是几十到几百个时钟的开销。
对于随机访问,单个 16 位读取不仅跨越总线宽度边界而且恰好跨越缓存线边界,这不仅会在处理器端产生一个额外的时钟,而且在最坏的情况下,它可能会导致额外的缓存线提取,即几十到几百个额外的时钟周期。如果您正在遍历一系列碰巧未对齐的事物(结构/联合可能是一个示例,具体取决于编译器和代码),那么无论如何都会发生额外的缓存行提取,如果事物数组有点过时一端或两端,那么如果阵列对齐,您可能仍然会产生一两个更多的缓存行提取,而这些缓存行是您可以避免的。
这真的是读取的关键是在对齐区域之前或之后,您可能必须为您溢出的每一侧的每个区域进行转移。
写作有好有坏。随机读取速度较慢,因为事务必须停止,直到答案回来。对于随机写入,内存控制器拥有它需要的所有信息,包括地址、数据、字节掩码、传输类型等。所以它很容易忘记处理器已经完成它的工作,并且可以从它的角度调用事务完成,并且继续前行。自然而然地把太多的这些组合起来,或者对刚刚写入的东西进行读取,然后由于除了当前事务之外的先前写入的完成,处理器会停止。
例如,未对齐的 16 位写入不仅会产生额外的读取周期,而且假设 32 或 64 位宽的总线每个位置一个字节,因此您必须对最近的内存(缓存或德拉姆)。因此,取决于处理器和内存控制器如何实现它,它可以是两个单独的读取-修改-写入事务(不太可能,因为这会产生两倍的开销),或者是双倍宽度读取、修改这两个部分和双倍宽度读取。在开销之上产生两个额外的时钟,开销也加倍。如果它是对齐的总线宽度写入,则不需要读取-修改-写入,则保存读取。
我也最熟悉ARM。Arm 传统上会通过中止来惩罚未对齐的访问,您可以将其关闭,并且您将获得总线的轮换而不是溢出,这将产生一些不错的免费赠品字节序交换。更现代的手臂核心将容忍并实施未对齐的传输。了解例如,针对非 64 位对齐地址存储多个 4 个或更多寄存器不被视为未对齐访问,即使它是对既不是 64 位也不是 128 位对齐的地址的 128 位写入。在这种情况下,处理器所做的是将其分为 3 次写入、对齐的 32 位写入、对齐的 64 位写入和对齐的 32 位写入。内存控制器不必处理未对齐的东西。这适用于诸如存储多个合法的事情。无论如何,我熟悉的核心不会执行超过 2 的写入长度,一个 8 寄存器存储多个,不是 4 写入的单个长度,它是 2 单独的两次写入长度。但是加载 8 个寄存器的倍数,只要它在 64 位地址上对齐,就是单个长度为 4 的事务。我很确定,由于总线端没有用于读取的屏蔽,所以一切都以总线宽度为单位,没有理由在一个不是 64 位对齐到 3 个事务中的地址上打破 4 个寄存器加载倍数,只需读取 3 的长度。当处理器读取单个字节时,您无法从总线上看出您所看到的只是 64 位读取的 AFAIK。处理器剥离字节通道。如果处理器/总线确实关心它是 arm、x86、mips 等,那么您肯定会看到单独的传输。
每个人都这样做吗?没有较旧的处理器(不考虑 arm 或 x86)会给内存控制器带来更多负担。我不知道现代 x86 和 mips 等是做什么的。
您的 malloc 示例。首先,您不会看到 4Kbytes 的单总线传输,无论如何,4k 将被分解成可消化的位。首先,它必须对内存管理单元执行一对多的总线周期才能找到物理地址和其他属性(这些答案可以被缓存以使它们更快,但有时它们必须一路走慢 DRAM)因此,对于该示例,唯一重要的传输是分割 4k 边界的对齐传输,例如 16 位传输,以便 mmu 系统完全工作,唯一支持的方法是必须将其转换为两个独立的在这些物理地址空间中发生的 8 位传输,是的,这实际上使 mmu 查找周期、缓存/DRAM 总线周期等的所有内容加倍。除了那个边界之外,你的 8k 被分割并没有什么特别之处。您的大部分周期将在两个 4k 页面之一内,因此它看起来像任何其他随机访问,当然重复/顺序访问可以获得缓存的好处。
简短的回答是,无论您在哪个平台上,1) 平台都会中止未对齐的传输,或者 2) 在路径中的某处,由于比较的未对齐访问,路径中的某个位置会增加一个或多个(数十个/数百个)到对齐的访问。