我是程序员初学者,但我想更深入地了解这些事情。我做了一些研究并阅读了很多文字,但我还没有理解一些事情......
编码基本内容时(在C中):
int myNumber;
myNumber = 3;
printf("Here's my number: %d", myNumber);
我发现(主要在32位CPU上)整数取代32位= 4字节。所以在我的代码的第一行CPU进入内存。存储器是字节可寻址的,因此CPU为我的变量选择4个连续字节,并将地址存储到第一个(或最后一个)字节。
在我的代码的第二行,CPU使用他存储的MyNumber变量的地址,转到内存中的那个地址,找到32位的保留空间。他现在的任务是在那里存储数字“3”,所以他用序列00000000-00000000-00000000-00000011填充这四个字节。 在第三行它执行相同操作 - CPU转到内存中的该地址并加载存储在该地址中的数字。
(第一个问题 - 我理解对吗?)
我不明白的是:
在32位CPU中,该地址的大小(指向该变量的指针)为4字节。 (这就是为什么32位CPU可以使用最大4GB的内存 - 因为只有2 ^ 32个不同的二进制长度32的地址)
现在, CPU存储这些地址的位置?他是否有某种自己的内存或缓存来存储它们?并且为什么它将32位长地址存储到32位长整数?简单地在其缓存中存储实际数字而不是指向大小相同时的指针是不是更好? / p>
最后一个 - 如果它存储在自己的缓存中的某个地方,那些整数和长度的地址是相同的(4个字节),它将需要与实际变量存储地址完全相同的空间。但变量最多可占用4GB的空间,因此CPU必须有4GB的空间来存储这些变量的地址。这听起来很奇怪..
谢谢你的帮助!
我试图理解这一点,但它太难了......: - [
答案 0 :(得分:5)
(第一个问题 - 我理解对吗?)
首先要认识到的是,该值可能根本不存储在主存储器中。编译器可能决定将其存储在寄存器中,因为这更为理想。 1
内存是字节可寻址的,因此CPU为我的变量选择4个连续字节,并将地址存储到第一个(或最后一个)字节。
假设编译器决定将其存储在主存储器中,那么是的,在32位机器上,int
通常是4个字节,因此将分配4个字节用于存储。
32位CPU中该地址的大小(指向该变量的指针)为4字节。 (这就是为什么32位CPU可以使用最大4GB的内存 - 因为只有2 ^ 32个不同的二进制长度32的地址)
请注意,int
的宽度和指针的宽度不必相同,因此不一定具有地址空间大小的连接。
现在,CPU存储这些地址的位置?
在局部变量的情况下,地址实际上硬编码到可执行文件本身,通常作为堆栈指针的偏移量。
在动态分配对象(即已经malloc
- ed的东西)的情况下,程序员通常会维护一个相应的指针变量(否则会出现内存泄漏!)。该指针也可以动态分配(在复杂数据结构的情况下),但是如果你回到足够远的地方,你最终会得到一个局部变量。在这种情况下,上述规则适用。
但变量最多可占用4GB的空间,因此CPU必须有4GB的空间来存储这些变量的地址。
如果你的程序独立地malloc
包含数百万int
个,那么是的,你最终会得到指针所需的存储空间。但大多数程序看起来并不像那样。您通常会分配更大的对象(如数组或大结构)。
缓存
where 存储内容的细节是特定于体系结构的。在现代的x86上,CPU和主内存之间通常有2到3层缓存。但缓存不能独立寻址; CPU无法决定将int
存储在缓存中而不是主内存中。相反,缓存实际上是主存储器子集的冗余副本。
另一件需要考虑的事情是,在为对象分配存储时,编译器通常会处理虚拟地址。在现代的x86上,它们通过专用硬件映射到物理地址(即与主存储器中的物理存储字节相对应的地址),以及OS支持。
<小时/> <子> 1。或者,编译器可能能够完全优化它。
答案 1 :(得分:3)
在我的代码的第二行,CPU使用他存储的MyNumber变量地址,转到内存中的那个地址,找到32位预留空间。
几乎正确。内存基本上是非结构化的。 CPU无法看到有32位“保留空间”。但是CPU被指示读取32位数据,因此它从指定的地址开始读取32位数据。然后它只是希望/假设那些32位实际上包含一些有意义的东西。
现在,CPU存储这些地址的位置?他有自己的内存或缓存存储吗?为什么它将32位长地址存储到32位长整数?简单地在其缓存中存储实际数字而不是指向大小相同时的指针不是更好吗?
CPU有少量寄存器,它可用于存储数据(通用CPU有8,16或32个寄存器,因此它们只能保存您正在工作的特定变量在这里和现在)。因此,首先回答最后一部分,是的,编译器当然可能(并且可能会)生成代码以将int
存储到寄存器中,而不是将其存储在内存中,并告诉CPU从中加载它指定的地址。
至于问题的其他部分:最终,程序的每个部分都存储在内存中。部分内容是指令流,其中一部分是散布在内存中的数据块。
有一些技巧可以帮助找到CPU所需的数据:程序内存的一部分包含堆栈,它通常在范围内存储局部变量。 CPU始终在其中一个寄存器中维护指向堆栈顶部的指针,因此只需通过修改具有固定偏移量的堆栈指针,就可以轻松地在堆栈上定位数据。指令可以直接包含这样的偏移,因此为了读取你的int,编译器可以例如生成在你输入函数时将int写入堆栈顶部的代码,然后当你需要引用该函数时,读取在堆栈指针指向的地址处找到的数据的代码,以及定位变量所需的小偏移量。
答案 2 :(得分:0)
并且还要记住,程序看到的地址可能不是(或者很少是)从“内存开头”开始的物理地址或者是0.通常它们偏移到内存管理器的特定内存块中通过base + offest知道真实地址和访问作为真实数据存储。
我们确实需要内存,因为缓存有限; - )
马里奥
答案 3 :(得分:0)
CPU内部有一个寄存器,其中包含要执行的下一条指令的地址。指令本身将信息保存在变量所在的位置。如果变量被优化,则指令可以指向寄存器,但是通常,指令将具有被访问的变量的地址。编译并加载到内存后,您的代码已嵌入所有内容!我建议使用汇编语言来更好地理解所有这些。祝你好运!