【问题标题】:What exactly is "memory" in C Programming?C 编程中的“内存”到底是什么?
【发布时间】:2020-07-15 14:29:56
【问题描述】:

我很想知道“记忆”究竟代表什么。

当我编译并执行这段代码时:

#include <stdio.h>
  
int main(void)
{
   int n = 50;
   printf("%p\n", &n);

}

我们知道,我们得到一个十六进制输出:

0x7ffeee63dabc

这个十六进制地址在物理上代表什么?它是我计算机 L1 缓存的一部分吗?内存?固态硬盘?

我在哪里可以阅读更多关于此的信息,任何参考资料都会有所帮助。谢谢。

一些背景: 经过几年的休息后,我最近重新开始学习计算机科学(我在该行业中作为低代码/无代码 Web 开发人员工作),并意识到我的知识存在一些空白,我想补充一下.

在学习 C(通过 CS50x)我在 Memory 的那一周。我意识到我实际上并不知道这指的是什么记忆。该课程假设学生已经知道这一点,或者它与本课程的上下文无关(这是一门介绍课程,因此抽象对于避免陷入兔子洞是有意义的),但我很好奇,我会喜欢追着它找出答案。

【问题讨论】:

标签: c memory computer-science


【解决方案1】:

计算机体系结构 101

  • 在您的计算机中有 CPU 芯片和 RAM 芯片。
  • CPU 的工作是计算事物。 RAM 的工作是记住事物。
  • CPU 负责。当它想记住某事或查找它正在记住的某事时,它会询问 RAM。
  • RAM 有一堆可以存储东西的插槽。每个插槽包含 1 个字节。槽号(不是槽号in,而是槽号of)称为地址。每个插槽都有不同的地址。它们从 0 开始向上:0、1、2、3、4,......就像街道上的信箱,但从 0 开始。
  • CPU 告诉 RAM要记住哪个的方法是使用一个称为地址的数字。
  • CPU 可以说:“将数字 126 放入插槽 73224。”它可以说:“插槽 97221 中的数字是多少?”
  • 我们通常用十六进制写槽号(地址),前面加上 0x 以提醒我们它们是十六进制的。这是传统。
  • CPU 如何知道它想访问哪个地址?很简单:程序告诉它。

操作系统 101

  • 操作系统的任务是保持系统平稳运行
  • 当允许错误程序访问不属于它们的内存时,不会发生这种情况。
  • 因此操作系统决定了程序可以访问哪些内存,以及不允许访问哪些内存。它告诉 CPU 这个信息。
  • “我可以访问此内存吗?”信息适用于称为“页面”的 4 KB 块。您可以访问整个页面,也可以不访问。那是因为如果每个字节都有单独的访问信息,您将需要浪费一半的 RAM 来存储访问信息!
  • 如果您尝试访问操作系统表示您无法访问的页面中的地址,CPU 会自动连接到操作系统,然后操作系统会停止运行您的程序。

操作系统 102

  • 还记得 Windows 95 天的这个闪亮的新“虚拟内存”功能吗?
  • “虚拟内存”是指您的程序使用的地址不是真正的 RAM 地址。
  • 每当您访问地址时,CPU 都会查找实际地址。这也使用页面。因此操作系统可以使任何“地址页面”转到任何“真实页面”。
    这些不是官方术语 - 操作系统设计人员实际上说任何“虚拟页面”都可以“映射”到任何“物理页面”。
  • 如果操作系统想要一个物理页面但没有剩余,它可以选择一个已经使用过的,将其数据保存到磁盘上,稍微注意它在磁盘上,然后它可以重用该页面。
  • 如果程序试图访问磁盘上的页面怎么办?操作系统对 CPU 撒谎:它说“不允许该程序访问此页面”。即使是允许的。
  • 当 CPU 与操作系统通话时,操作系统不会停止程序。它暂停程序,找到一些else的东西存储在磁盘上以腾出空间,读入程序想要的页面的数据,然后取消暂停程序并告诉CPU“实际上,他被允许访问现在这个页面。”巧妙的把戏!
  • 这就是虚拟内存。 CPU 不知道磁盘上的页面和未分配的页面之间的区别。您的程序不知道磁盘上的页面和不在磁盘上的页面之间的区别。当您的程序必须从磁盘中获取某些内容时,它只是遇到了一点小问题。
  • 了解虚拟页面是否实际存储在 RAM 中(在物理页面中)或是否存储在磁盘上的唯一方法是询问操作系统。
  • 虚拟页码不必从 0 开始;操作系统可以选择它想要的任何虚拟页码。

计算机体系结构 102

  • 高速缓存是 CPU 中的一小部分内存,因此它不必一直向 RAM 芯片查询。
  • CPU 第一次想从某个地址读取时,它会询问 RAM 芯片。然后,它从缓存中选择要删除的内容,将其删除,然后将刚刚读取的值放入缓存中。
  • 每当 CPU 想要从某个地址读取数据时,它都会首先检查它是否在缓存中。
  • 缓存中的内容在 RAM 中。这不是一个或另一个。
  • 缓存通常存储 64 字节的块,称为 缓存行。不是页面!
  • 没有一种很好的方法可以知道缓存行是否存储在缓存中。连操作系统都不知道。

编程语言设计101

C 不想让你知道所有这些东西。

C 是一组关于如何编写程序的规则。设计 C 的人不想解释所有这些东西,所以他们制定了关于指针能做什么和不能做什么的规则,这就是它的结束。

例如,该语言不了解虚拟内存,因为并非所有类型的计算机都有虚拟内存。洗碗机或微波炉都没有用,会浪费钱。

这个十六进制地址在物理上代表什么?它是我计算机 L1 缓存的一部分吗?内存?固态硬盘?

地址 0x7ffeee63dabc 表示虚拟页面 0x7ffeee63d 内的地址 0xabc。它现在可能在您的 SSD 上或 RAM 中;如果您访问它,那么它必须进入 RAM。它目前也可能在缓存中,但没有好的方法可以判断。无论去哪里,地址都不会改变。

【讨论】:

  • 顺便说一句,这些不是基于真实的课程编号。我并不是说你应该期望在这些特定的课程中学习这些东西。他们只是为了整理一下答案。
  • 为了跟进这个评论,我想指出大多数 CS 系统普遍存在的特征:抽象与实现。这是一个很好的抽象示例:编写 C 的程序员主要使用内存的槽值模型(如本答案的 CompArch 101 部分中使用的那样)。这是虚拟内存抽象的一部分。系统的其余部分(C 库、操作系统、CPU 缓存、内存控制器、RAM、HDD/SSD)都一起工作来实现这个抽象。在这些部分中有很多很酷的细节需要了解,@user253751 很好地指出了其中一些。
  • 很好的解释!
  • @MattDMo 谢谢!我认为重要的是要确保基本的基础非常清楚。就像地址是 CPU 告诉 RAM 什么要记住或检索的方式。
  • 嗯,它对我有用。我已经知道了很多东西,但是你把它们联系在一起并提供了更多的背景信息。在多年的 Python 之后,我才刚刚开始学习 C,所以甚至不得不考虑内存分配是新的。这就是为什么我喜欢 SO!
【解决方案2】:

您应该将内存视为从地址到值的抽象映射,仅此而已。

在您尝试针对非常特定的硬件进行优化之前,您的实际硬件是否将其实现为单个内存块或复杂的缓存层次结构都无关紧要,99% 的时间您都不想这样做。

【讨论】:

  • s/99/99.9999999/
【解决方案3】:

一般来说,内存是临时存储或非易失性存储的任何东西。机器关闭时会丢失临时内存,通常称为 RAM 或简称为“内存”。非易失性保存在硬盘、闪存驱动器、EEPROM 等中,通常称为 ROM 或存储。

缓存也是一种临时内存,但它们仅被称为缓存,不被视为 RAM 的一部分。您 PC 上的 RAM 也称为“物理内存”或“主内存”。

在编程时,所有变量通常都在主内存中(稍后会详细介绍)并在使用时被带到缓存(L1、L2 等)。但缓存对于应用开发者来说大部分是透明的。

在我回答你的问题之前,还有一件事要提。程序的地址不一定是物理内存的地址。这些地址通过 MMU(内存保护单元)或类似的 CPU 功能从“虚拟地址”转换为“物理地址”。操作系统处理 MMU。使用 MMU 的原因有很多,两个原因是隐藏和保护操作系统内存和其他应用程序内存免受程序错误的内存访问。这样一个程序就不能访问或改变操作系统或其他程序的内存。

此外,当没有足够的 RAM 来存储应用程序请求的所有内存时,操作系统可以将部分内存存储在非易失性存储中。使用虚拟地址,程序无法轻易知道内存实际上是在 RAM 中还是在存储器中。这样程序可以分配比 RAM 更多的内存。这也是程序在消耗大量内存时会变得非常慢的原因:需要很长时间才能将数据从存储中带回主内存。

因此,您要打印的地址很可能是虚拟地址。

您可以在此处阅读有关这些主题的内容:

https://en.wikipedia.org/wiki/Memory_management_(operating_systems)

https://en.wikipedia.org/wiki/Virtual_memory

【讨论】:

    【解决方案4】:

    从 C 标准的角度来看,内存是对象 storage。它的工作原理和组织方式留给实现。

    即使从 C 的角度打印指针也是没有意义的(从实现的角度来看,它可以提供信息和有趣)并且毫无意义。

    【讨论】:

      【解决方案5】:

      如果您的代码在现代操作系统下运行1,指针值几乎肯定对应于virtual memory 地址,而不是物理地址。有一个虚拟内存系统可以将您的代码看到的虚拟地址映射到主内存 (RAM) 中的物理地址,但是随着页面的换入和换出,物理地址可能会发生变化。


      1. 对于台式机,任何比 90 年代中期更新的东西。对于大型机和小型机,几乎任何比 60 年代中期更新的东西。

      【讨论】:

        【解决方案6】:

        它是我计算机 L1 缓存的一部分吗?内存?固态硬盘?

        简短的回答是 RAM。此地址通常与 RAM 中的唯一位置相关联。长答案是,嗯 - 这取决于!

        当今的大多数机器都有一个内存管理单元 (MMU),它位于 CPU 和连接到它的外围设备之间,将程序看到的“虚拟”地址转换为实际指代物理连接到总线的东西的真实地址.设置 MMU 并为程序分配内存区域通常是操作系统的工作。这允许一些很酷的东西,例如与其他正在运行的程序共享代码/数据等等。

        因此,您在此处看到的地址可能根本不是 RAM 位置的实际物理地址。但是,在 MMU 的帮助下,操作系统可以准确快速地将这个数字映射到 RAM 中某处的实际物理内存位置,并允许您将数据存储在 RAM 中。

        现在,对 RAM 的任何访问都可以缓存在一个或多个可用缓存中。或者,您的程序内存可能会临时移动到磁盘(交换文件)以为另一个程序腾出空间。但所有这些对程序员来说都是完全自动和透明的。就您的程序而言,您正在直接读取或写入可用 RAM,并且地址是您正在访问的 RAM 中唯一位置的句柄。

        【讨论】:

        • 投反对票的人愿意解释什么是错的吗?
        猜你喜欢
        • 2023-03-22
        • 1970-01-01
        • 1970-01-01
        • 2021-11-12
        • 2020-09-18
        • 2013-05-29
        • 2014-04-15
        • 2011-03-06
        相关资源
        最近更新 更多