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

Where are variables in C++ stored?

本文关键字:存储 在哪里 变量 C++      更新时间:2023-10-16

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

在 RAM 或处理器的缓存中?

命名变量存储:

  • 在堆栈上,如果它们是函数局部变量.
    C++称之为"自动存储">1,并不要求它实际上是 asm 调用堆栈,在一些罕见的实现中,它不是。 但在主流实现中确实如此。
  • 在每个进程数据区域中,如果它们是全局的还是static .
    C++称之为"静态存储类";它在ASM中通过将/保留字节放在section .data.bss.rodata或类似的东西中来实现。

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

  • 在堆上(C++称之为动态存储(,分配有 newmalloc
    在 asm 中,这意味着调用分配器函数,如果其自由列表为空,则最终可能会通过某种系统调用从操作系统获取新内存。 "堆"不是现代操作系统/C++实现中的单个连续区域。

C 和 C++ 不执行自动垃圾回收,命名变量本身不能位于动态存储("堆"(中。 动态存储中的对象是匿名的,而不是由其他对象指向,其中一些可能是适当的变量。 (结构或类类型的对象,而不是像 int 这样的基元类型,可以让你引用这个匿名对象中的命名类成员。 在成员函数中,它们甚至看起来相同。

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

<小时 />

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

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

<小时 />

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

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

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

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

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

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

进入 CPU 缓存

的内容超出了编译器的控制范围,CPU 自行决定缓存什么以及如何缓存它(取决于诸如">最近是否使用过这些数据?"或">是否可以预期数据很快就会再次使用?"(,当然缓存的大小也有很大的影响。

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

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

C++中的变量存储在堆栈或堆上。

叠:

int x;

堆:

int *p = new int;

话虽如此,两者都是 RAM 中构建的结构。

如果您的 RAM 使用率很高,尽管 Windows 可以将其换成磁盘。

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

C++不知道

处理器的缓存。

当您运行用C++或任何其他语言编写的程序时,您的 CPU 将在缓存中保留"流行"RAM 块的副本。 这是在硬件级别完成的。

不要将 CPU 缓存视为"其他"或"更多"内存...它只是一种将一些 RAM 块放在附近的机制。

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

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

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

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

如果你有任何中途体面的优化编译器,局部变量通常会存储在处理器的寄存器文件中。 变量在读取和写入时将在 RAM、缓存和寄存器文件之间来回移动,但它们通常始终在 RAM/ROM 中具有副本,除非编译器决定没有必要。

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

静态

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

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

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

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

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

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

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

 {
   struct foobar *ptr
      = (struct foobar *) malloc (sizeof (struct foobar));
   ptr->name = x;
   ptr->next = current_foobar;
   current_foobar = ptr;
 }

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

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

当应用程序使用数据时,必须在使用数据之前将其移动到CPU的寄存器中,但是这是非常不稳定和临时存储的。