【发布时间】:2015-11-15 15:33:23
【问题描述】:
我正在尝试更深入地研究内存分配、寻址,并且我还遇到了堆栈对齐的概念,通常是内存对齐。我想了解我是否正确掌握了所有概念。我的问题都涉及当今的计算机和处理器,例如我们笔记本电脑上的处理器。我想强调一下,我阅读了很多关于 stackoverflow 的其他问题,而我的大部分实际知识都来自它们。
我的第一个疑问与记忆词的概念有关。内存字不仅定义了寄存器和总线大小,还定义了基本的内存单元(例如,64 位架构上的 64 位,32 位架构上的 32 位 ecc)。但是,据我所知,每个地址都准确引用 1 字节 内存,而不管内存字的大小。所以我们可以说每个字节都有自己的地址。但是:
1) CPU 不能访问单个字节但它访问包含该字节的整个字是否正确?因此,如果请求特定字节(例如,我访问 char 的直接地址),它会访问整个单词并进行一些计算以删除其他部分并返回确切的字节?
2) 那么 CPU 实际上只能访问内存字单元并且每个内存字从偶数地址开始,是单元本身的倍数,这是否正确?
因此,例如,在 64 位架构上,内存字为 8 个字节,因此(示例)地址 0x2710(以 10 为基数的 10000)将是内存字的开头。如果我尝试访问 0x2711,CPU 将从 0x2710 访问到 0x2717,然后只提取单个字节。对吗?!
第二。正如我之前所说,我遇到了内存对齐。一开始它让我有些困惑。请帮助我理解我是否做对了。该问题本质上与性能有关,或者在某些情况下,与需要 16 字节对齐的 SSE 特定指令有关。例如,在第一种情况下,如果(在 64 位架构上)跨 2 个内存字存储 8 字节数据(例如,一个 long int),则 CPU 需要 2 次访问而不是一次访问。
3) 所以,举个例子:
0x2710 | .... |
0x2711 | .... |
0x2712 | .... |
0x2713 | .... |
0x2714 | data |
0x2715 | data |
0x2716 | data |
0x2717 | data |
0x2718 | data |
0x2719 | data |
0x2720 | data |
0x2721 | data |
0x2722 | .... |
0x2723 | .... |
0x2724 | .... |
0x2725 | .... |
在这种情况下,内存未对齐。正确的?通过对齐,CPU 将仅存储来自 0x2710 的数据,或者,如果占用到 0x2713,它将插入填充,然后存储来自 0x2718 的 8 字节数据。对吧?
4) 因此,内存对齐基本上包括仅从地址开始的多字节数据,这些数据是所需字节单元的倍数(通常是内存字本身,还有其他自定义单元 - 例如,在 GCC 上使用 mpreferred-stack-boundaries)。我说“多字节”数据是因为如果数据只有一个字节,它总是只适合一个单词。这一切都正确吗?
5) 编译器应用内存对齐?因此,它是在二进制(汇编)代码中应用还是在存储数据时由 CPU 以某种方式应用? 而且,这不是很大的内存浪费吗?我的意思是,如果总是应用它,每个多字节数据也可能意味着填充!我可能会浪费大量内存空间!
就是这样!谢谢,真的提前谢谢!
【问题讨论】:
-
我开始写回复,但一半的答案是“取决于 CPU”。 en.wikipedia.org/wiki/Data_structure_alignment 似乎很好地解释了其余部分。
-
啊哈哈哈谢谢!我已经阅读了维基百科页面。我知道它非常依赖 CPU,我只是想了解,一般来说,我写的内容是否适用于现代处理器。
标签: c memory-management stack memory-address memory-alignment