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

12 c++ architecture memory computer-architecture

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

在RAM或处理器的缓存中?

Dan*_*ski 36

变量存储:

  • 在堆栈上,如果它们是auto-matic函数 - 局部变量
  • 在堆上,如果它们被分配了newmalloc等等(在评论中说"变量存储在堆中"的含义的细节)
  • 在每个进程数据区域中,如果它们是全局的或 static

当然,这都在RAM中.缓存对用户空间进程是透明的,尽管它可能会对性能产生不利影响.

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

  • 实际上,变量不存储在堆中.您可能有一个指向堆中某些内容的变量,但变量本身将位于寄存器中,堆栈上或静态分配. (7认同)
  • @Kristopher:嗯,你的陈述并不完全正确.类ojects*的成员变量在堆上存储/分配. (3认同)

T.E*_*.D. 16

对于C++,一般来说,正确的答案是"编译器决定放置它们的地方".除非你以某种方式指导编译器,否则你不应该做出其他假设.有些变量可以完全存储在寄存器中,有些变量可能完全被优化掉,并被文字替换.对于某些平台上的一些编译器,常量可能实际上最终在ROM中.

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

在等式的另一端,未使用的RAM有时会在大多数操作系统上换成磁盘.因此有可能(但不太可能)在某些时刻您的变量实际存储在磁盘上.:-)


Mec*_*cki 9

变量通常存储在RAM中.这可以在堆上(例如,所有全局变量通常都会在那里)或在堆栈上(在方法/函数中声明的所有变量通常都在那里).堆栈和堆都是RAM,只是不同的位置.指针有不同的规则.指向某事物(内存块,对象等)本身的指针通常遵循上面的规则(在函数中声明的指针存储在堆栈中),但它指向的数据(内存块本身或对象)你用new创建的)存储在堆上.您可以创建指向堆栈的指针(例如"int a = 10; int*b =&a;",b指向a,a存储在堆栈中),但使用malloc或new的内存分配计入堆内存.

进入CPU缓存的是超出编译器控制的范围,CPU决定自己要缓存什么以及如何长时间缓存它(取决于"最近是否已使用此数据?"或"是否预期数据被使用"等因素很快又一次?"当然,缓存的大小对CPU保存数据的时间有很大影响 - 它们拥有的缓存越多,缓存的数据就越多,在释放缓存之前保存数据的时间就越长新数据的空间).

编译器可能只决定数据是否进入CPU寄存器.如果连续访问数据,通常会将数据保留在那里(因为寄存器访问速度比缓存快,而且比RAM快得多).某些系统上的某些操作实际上只能在数据位于寄存器中时执行 - 但编译器将决定是否在对其执行操作后立即将数据复制回RAM,或者将其保留在那里以对其执行更多操作在将其写回RAM之前.如果可能的话,它总会尝试将最常访问的数据保存在寄存器中,如果寄存器用完了(取决于你的CPU有多少个寄存器),它将决定是否最好将数据写回RAM(并获取)从那里再次需要它),或者只是暂时将数据交换到堆栈上,然后再将其从那里取回(即使堆栈也是RAM,通常使用堆栈也更快,因为CPU通常无论如何都要缓存堆栈的顶部,因此推送到堆栈并从堆栈弹出可能实际上只是写入缓存并从那里读回,数据可能永远不会到达内存.然而,当代码流从一个方法/函数跳转到另一个方法/函数时,通常所有寄存器都被写回内存,因为编译器很难确定被调用的函数/方法不会访问寄存器数据来自的存储器以及何时如果没有写回数据,函数可能会看到内存中仍然存在旧值,因为新值仅在寄存器中并且尚未写回.通常使用堆栈的速度更快,因为CPU通常无论如何都会缓存堆栈顶部,因此从堆栈推送和弹出可能实际上只是写入缓存并从那里读回,数据可能永远不会到达内存.然而,当代码流从一个方法/函数跳转到另一个方法/函数时,通常所有寄存器都被写回内存,因为编译器很难确定被调用的函数/方法不会访问寄存器数据来自的存储器以及何时如果没有写回数据,函数可能会看到内存中仍然存在旧值,因为新值仅在寄存器中并且尚未写回.通常使用堆栈的速度更快,因为CPU通常无论如何都会缓存堆栈顶部,因此从堆栈推送和弹出可能实际上只是写入缓存并从那里读回,数据可能永远不会到达内存.然而,当代码流从一个方法/函数跳转到另一个方法/函数时,通常所有寄存器都被写回内存,因为编译器很难确定被调用的函数/方法不会访问寄存器数据来自的存储器以及何时如果没有写回数据,函数可能会看到内存中仍然存在旧值,因为新值仅在寄存器中并且尚未写回.数据可能永远不会到达内存.然而,当代码流从一个方法/函数跳转到另一个方法/函数时,通常所有寄存器都被写回内存,因为编译器很难确定被调用的函数/方法不会访问寄存器数据来自的存储器以及何时如果没有写回数据,函数可能会看到内存中仍然存在旧值,因为新值仅在寄存器中并且尚未写回.数据可能永远不会到达内存.然而,当代码流从一个方法/函数跳转到另一个方法/函数时,通常所有寄存器都被写回内存,因为编译器很难确定被调用的函数/方法不会访问寄存器数据来自的存储器以及何时如果没有写回数据,函数可能会看到内存中仍然存在旧值,因为新值仅在寄存器中并且尚未写回.


Bri*_*ndy 6

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

堆:

int x;
Run Code Online (Sandbox Code Playgroud)

堆:

int *p = new int;
Run Code Online (Sandbox Code Playgroud)

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

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

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


Dre*_*ann 6

C++不知道您的处理器缓存.

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

不要将CPU缓存视为"其他"或"更多"内存......它只是一种机制,可以将一些RAM保存在附近.


Ada*_*eld 1

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

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

  • Stroustrup 经常谈论存储在 ROM 中的变量。C++ 标准委员会也是如此(http://www.open-std.org/jtc1/sc22/wg21/docs/PDTR18015.pdf 第 75 页)。实际上,它不是物理 ROM,而是数据可执行文件的一部分(在 ELF 中是 .text 部分)。 (3认同)