17

C ++中的变量存储在哪里?

在 RAM 或处理器的缓存内?

4

9 回答 9

43

命名变量被存储:

  • 在堆栈上,如果它们是函数局部变量。
    C++ 称之为“自动存储” 1并且并不要求它实际上是 asm 调用堆栈,在一些罕见的实现中它不是。但在主流实现中确实如此。
  • 如果它们是全局的或static.
    C++ 称之为“静态存储类”;section .data它是在 asm 中通过在、.bss.rodata或类似文件中放置/保留字节来实现的。

如果变量是用int *p = new int[10];或类似初始化的指针,则指针变量p将如上所述进入自动存储或静态存储。内存中指向的对象是:

  • 在堆上(C++ 称为动态存储),使用newormalloc等​​进行分配。
    在 asm 中,这意味着调用分配器函数,如果空闲列表为空,则该函数最终可能通过某种系统调用从操作系统获取新内存。“堆”不是现代操作系统/C++ 实现中的单个连续区域。

C 和 C++ 不进行自动垃圾回收,命名变量本身不能在动态存储(“堆”)中。动态存储中的对象是匿名的,除了被其他对象指向之外,其中一些可能是适当的变量。(结构或类类型的对象,与 类似的原始类型相反int,可以让您引用此匿名对象中的命名类成员。在成员函数中,它们甚至看起来相同。)

这就是为什么您不能(安全/有用地)返回指针或对局部变量的引用。


当然,这一切都在 RAM 中。缓存对用户空间进程是透明的,尽管它可能会明显影响性能。

编译器可以优化代码以将变量存储在寄存器中。这是高度依赖编译器和代码的,但是好的编译器会积极地这样做。


脚注 1:有趣的事实:auto在 C++03 和更早版本中,仍然在 C 中,表示自动存储类,但现在(C++11)它推断类型。

于 2008-10-23T17:22:29.060 回答
17

一般来说,对于 C++,正确的答案是“无论你的编译器决定把它们放在哪里”。除非您以其他方式指示编译器,否则您不应做出假设。有些变量可以完全存储在寄存器中,有些可能会被完全优化掉并在某处被文字替换。对于某些平台上的某些编译器,常量实际上可能最终在 ROM 中。

您关于“处理器的缓存”的部分问题有点混乱。有一些工具可以指导处理器如何处理其缓存,但一般来说,这是处理器的事情,您应该不可见。您可以将缓存视为 CPU 进入 RAM 的窗口。几乎所有内存访问都通过缓存。

另一方面,在大多数操作系统上,未使用的 RAM 有时会被换出到磁盘上。所以它可能(但不太可能)在某些时候你的变量实际上存储在磁盘上。:-)

于 2008-10-23T17:48:56.477 回答
13

变量通常存储在 RAM 中。这要么在堆上(例如全局变量、方法/函数中的静态变量),要么在堆栈上(例如在方法/函数中声明的非静态变量)。Stack 和 Heap 都是 RAM,只是位置不同。

指针有点特别。指针本身遵循上述规则,但它们指向的数据通常存储在堆上(使用 创建的内存块,使用创建的malloc对象new)。但是您可以创建指向堆栈内存的指针int a = 10; int * b = &a;b指向的内存aa存储在堆栈中。

进入 CPU 缓存的内容超出了编译器的控制范围,CPU 自行决定缓存什么以及缓存多长时间(取决于“最近是否使用过此数据? ”或“是否可以预期使用该数据很快又了吗? ”)当然,缓存的大小也有很大的影响。

编译器只能决定哪些数据进入 CPU 寄存器。通常,如果经常连续访问数据,则数据会保留在那里,因为寄存器访问速度比缓存快,而且比 RAM 快得多。某些系统上的某些操作实际上只有在数据在寄存器中时才能执行,在这种情况下,编译器必须在执行操作之前将数据移动到寄存器,并且只能决定何时将数据移回 RAM。

编译器将始终尝试将最常访问的数据保存在寄存器中。当一个方法/函数被调用时,通常所有的寄存器值都会被写回 RAM,除非编译器可以确定被调用的函数/方法不会访问数据来自的内存。同样在返回方法/函数时,它必须将所有寄存器数据写回 RAM,否则新值将丢失。返回值本身在某些 CPU 架构上的寄存器中传递,否则通过堆栈传递。

于 2008-10-23T17:34:21.280 回答
6

C++ 不知道处理器的缓存。

当你运行一个用 C++ 或任何其他语言编写的程序时,你的 CPU 会在缓存中保存一份“流行”的 RAM 块的副本。这是在硬件级别完成的。

不要将 CPU 缓存视为“其他”或“更多”内存……它只是一种将一些 RAM 块保持在附近的机制。

于 2008-10-23T18:25:58.120 回答
6

C++ 中的变量要么存储在堆栈上,要么存储在堆上。

堆:

int x;

堆:

int *p = new int;

话虽如此,两者都是内置在 RAM 中的结构。

如果您的 RAM 使用率很高,但 Windows 可以将其交换到磁盘。

当对变量进行计算时,内存将被复制到寄存器中。

于 2008-10-23T17:20:43.727 回答
4

我认为你混淆了两个概念。一、C++语言如何在内存中存储变量。第二,计算机和操作系统如何管理该内存。

在 C++ 中,变量可以在堆栈上分配,堆栈是保留给程序使用的内存,并且在线程启动时大小固定,或者在动态内存中可以使用 new 动态分配。如果代码分析允许,编译器还可以选择将变量存储在处理器中的寄存器上。这些变量永远不会看到系统内存。

如果变量最终进入内存,操作系统和处理器芯片组就会接管。基于堆栈的地址和动态地址都是虚拟的。这意味着它们可能在任何给定时间都驻留在系统内存中,也可能不驻留在系统内存中。in memory 变量可以存储在系统内存中,分页到磁盘上,或者可以驻留在处理器上或处理器附近的高速缓存中。因此,很难知道这些数据实际存在于何处。如果一个程序有一段时间没有空闲,或者两个程序正在竞争内存资源,则可以将该值保存在页面文件中的磁盘中,并在程序轮到运行时恢复。如果变量对于正在完成的某些工作是本地的,则可以在处理器缓存中对其进行多次修改,然后最终将其刷新回系统内存。您编写的代码永远不会知道发生了这种情况。

于 2008-10-23T18:14:55.770 回答
1

变量可以保存在许多不同的地方,有时甚至不止一个地方。加载程序时,大多数变量都放在 RAM 中;有时,声明的变量会const放在 ROM 中。每当访问一个变量时,如果它不在处理器的缓存中,就会导致缓存未命中,并且当变量从 RAM/ROM 复制到缓存中时,处理器将停止。

如果您有任何不错的优化编译器,则局部变量通常会存储在处理器的寄存器文件中。变量将在 RAM、缓存和寄存器文件之间来回移动,因为它们被读取和写入,但它们通常总是在 RAM/ROM 中有一个副本,除非编译器认为没有必要。

于 2008-10-23T17:20:08.847 回答
1

C++ 语言通过 C++ 程序中的变量支持两种内存分配:

静态分配是在声明静态或全局变量时发生的。每个静态或全局变量定义一个固定大小的空间块。当您的程序启动(执行操作的一部分)时,空间被分配一次,并且永远不会被释放。当您声明一个自动变量(例如函数参数或局部变量)时,就会发生自动分配。自动变量的空间在输入包含声明的复合语句时分配,并在退出该复合语句时释放。自动存储的大小可以是变化的表达式。在其他 CPP 实现中,它必须是一个常数。第三种重要的内存分配,动态分配,不受 C++ 变量支持,但可用的库函数。动态内存分配

动态内存分配是一种技术,程序在运行时确定在哪里存储一些信息。当您需要的内存量或继续需要多长时间取决于程序运行之前未知的因素时,您需要动态分配。

例如,您可能需要一个块来存储从输入文件中读取的行;由于一行的长度没有限制,因此您必须动态分配内存,并在您阅读更多行时使其动态变大。

或者,您可能需要为输入数据中的每条记录或每个定义设置一个块;由于您无法提前知道会有多少,因此您必须在阅读时为每条记录或定义分配一个新块。

当您使用动态分配时,内存块的分配是程序明确请求的操作。当您想要分配空间时调用函数或宏,并使用参数指定大小。如果要释放空间,可以通过调用另一个函数或宏来实现。你可以随时随地做这些事情。

CPP 变量不支持动态分配;没有“动态”存储类,也永远不可能有一个 CPP 变量的值存储在动态分配的空间中。获得动态分配内存的唯一方法是通过系统调用,而引用动态分配空间的唯一方法是通过指针。因为不太方便,而且动态分配的实际过程需要更多的计算时间,程序员通常只在静态分配和自动分配都不起作用时才使用动态分配。

例如,如果要动态分配一些空间来保存 struct foobar,则不能声明其内容是动态分配的空间的 struct foobar 类型的变量。但是您可以声明一个指针类型的变量 struct foobar * 并为其分配空间地址。然后你可以在这个指针变量上使用运算符'*'和'->'来引用空间的内容:

 {
   struct foobar *ptr
      = (struct foobar *) malloc (sizeof (struct foobar));
   ptr->name = x;
   ptr->next = current_foobar;
   current_foobar = ptr;
 }
于 2013-01-17T14:38:04.020 回答
0

根据它们的声明方式,它们将存储在“”或“堆栈”中

堆是应用程序可以使用的动态数据结构。

当应用程序使用数据时,必须在它们被使用之前将其移动到 CPU 的寄存器中,但是这是非常易失的临时存储。

于 2008-10-23T17:21:07.347 回答