简体   繁体   English

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

[英]Where are variables in C++ stored?

Where are variables in C++ stored? C++中的变量存储在哪里?

Inside the RAM or the processor's cache?在 RAM 或处理器的缓存中?

Named variables are stored:命名变量存储:

  • On the stack, if they're function-local variables.在堆栈上,如果它们是函数局部变量。
    C++ calls this "automatic storage" 1 and doesn't require it to actually be the asm call stack, and in some rare implementations it isn't. C++ 称这种“自动存储”为1并且不要求它实际上是 asm 调用堆栈,在一些罕见的实现中它不是。 But in mainstream implementations it is.但在主流实现中确实如此。
  • In a per-process data area if they are global or static .在每个进程的数据区域中,如果它们是 global 或static
    C++ calls this "static storage class"; C++ 称之为“静态存储类”; it's implemented in asm by putting / reserving bytes in section .data , .bss , .rodata , or similar.它通过在section .data.bss.rodata或类似section .data放置/保留字节在 asm 中实现。

If the variable is a pointer initialized with int *p = new int[10];如果变量是一个用int *p = new int[10];初始化的指针int *p = new int[10]; or similar, the pointer variable p will go in automatic storage or static storage as above.或类似的,指针变量p将进入自动存储或静态存储,如上所述。 The pointed-to object in memory is:内存中指向的对象是:

  • On the heap (what C++ calls dynamic storage), allocated with new or malloc , etc.在堆上(C++ 称之为动态存储),用newmalloc等分配。
    In asm, this means calling an allocator function, which may ultimately get new memory from the OS via some kind of system call if its free-list is empty.在 asm 中,这意味着调用分配器函数,如果其空闲列表为空,则该函数最终可能会通过某种系统调用从操作系统获取新内存。 "The heap" isn't a single contiguous region in modern OSes / C++ implementations. “堆”不是现代操作系统/C++ 实现中的单个连续区域。

C and C++ don't do automatic garbage collection, and named variables can't themselves be in dynamic storage ("the heap"). C 和 C++ 不进行自动垃圾收集,命名变量本身不能处于动态存储(“堆”)中。 Objects in dynamic storage are anonymous, other than being pointed-to by other objects, some of which may be proper variables.动态存储中的对象是匿名的,除了被其他对象指向之外,其中一些可能是适当的变量。 (An object of struct or class type, as opposed to primitive types like int , can let you refer to named class members in this anonymous object. In a member function they even look identical.) (结构或类类型的对象,与像int这样的原始类型相反,可以让你引用这个匿名对象中的命名类成员。在成员函数中,它们甚至看起来是相同的。)

This is why you can't (safely/usefully) return a pointer or reference to a local variable.这就是为什么您不能(安全/有用地)返回指向局部变量的指针或引用的原因。


This is all in RAM, of course .当然,这一切都在 RAM 中 Caching is transparent to userspace processes, though it may visibly affect performance.缓存对用户空间进程是透明的,尽管它可能会明显影响性能。

Compilers may optimize code to store variables in registers.编译器可以优化代码以将变量存储在寄存器中。 This is highly compiler and code-dependent, but good compilers will do so aggressively.这是高度依赖于编译器和代码的,但好的编译器会积极地这样做。


Footnote 1: Fun fact: auto in C++03 and earlier, and still in C, meant automatic storage-class , but now (C++11) it infers types.脚注 1:有趣的事实: auto在 C++03 及更早版本中,并且仍然在 C 中,表示自动 storage-class ,但现在 (C++11) 它推断类型。

For C++ in general, the proper answer is "wherever your compiler decides to put them".一般来说,对于 C++,正确的答案是“无论你的编译器决定把它们放在哪里”。 You should not make assumptions otherwise, unless you somehow direct your compiler otherwise.您不应该以其他方式做出假设,除非您以其他方式指导编译器。 Some variables can be stored entirely in registers, and some might be totally optimized away and replaced by a literal somewhere.有些变量可以完全存储在寄存器中,有些变量可能会被完全优化掉并在某处替换为文字。 With some compilers on some platforms, constants might actually end up in ROM.对于某些平台上的某些编译器,常量实际上可能最终出现在 ROM 中。

The part of your question about "the processor's cache" is a bit confused.您关于“处理器缓存”的问题的一部分有点困惑。 There are some tools for directing how the processor handles its cache, but in general that is the processor's business and should be invisible to you.有一些工具可以指导处理器如何处理其缓存,但通常这是处理器的业务,您应该看不到。 You can think of the cache as your CPU's window into RAM.您可以将缓存视为 CPU 进入 RAM 的窗口。 Pretty much any memory access goes through the cache.几乎任何内存访问都通过缓存。

On the other end of the equation, unused RAM sometimes will get swapped out to disk on most OSes.另一方面,在大多数操作系统上,未使用的 RAM 有时会被换出到磁盘。 So its possible (but unlikely) that at some moments your variables are actually being stored on disk.因此,在某些时候您的变量实际上可能(但不太可能)存储在磁盘上。 :-) :-)

Variables are usually stored in RAM.变量通常存储在 RAM 中。 This is either on the Heap (eg global variables, static variables in methods/functions) or on the Stack (eg non-static variables declared within a method/function).这是在堆上(例如全局变量、方法/函数中的静态变量)或堆栈上(例如在方法/函数中声明的非静态变量)。 Stack and Heap are both RAM, just different locations.堆栈和堆都是 RAM,只是位置不同。

Pointers are a bit special.指针有点特殊。 Pointers themselves follow the rules above but the data they point to is typically stored on the Heap (memory blocks created with malloc , objects created with new ).指针本身遵循上述规则,但它们指向的数据通常存储在堆上(用malloc创建的内存块,用new创建的对象)。 Yet you can create pointers pointing to stack memory: int a = 10; int * b = &a;但是您可以创建指向堆栈内存的指针: int a = 10; int * b = &a; int a = 10; int * b = &a; ; ; b points to the memory of a and a is stored on the stack. b指向的存储器aa被存储在堆栈中。

What goes into CPU cache is beyond compilers control, the CPU decides itself what to cache and how to long to cache it (depending on factors like " Has this data been recently used? " or " Is it to be expected that the data is used pretty soon again? ") and of course the size of the cache has a big influence as well.进入 CPU 缓存的内容超出了编译器的控制,CPU 自行决定缓存什么以及缓存它的时间长短(取决于诸如“此数据最近是否被使用过? ”或“是否预期使用该数据?很快又回来了? ”)当然缓存的大小也有很大的影响。

The compiler can only decide which data goes into a CPU register.编译器只能决定哪些数据进入 CPU 寄存器。 Usually data is kept there if it's accessed very often in a row since register access is faster than cache and much faster than RAM.如果连续频繁访问数据,通常数据会保存在那里,因为寄存器访问速度比缓存快,比 RAM 快得多。 Some operations on certain systems can actually only be performed if the data is in a register, in that case the compiler must move data to a register before performing the operation and can only decide when to move the data back to RAM.某些系统上的某些操作实际上只能在数据位于寄存器中时才能执行,在这种情况下,编译器必须在执行操作之前将数据移至寄存器,并且只能决定何时将数据移回 RAM。

Compilers will always try to keep the most often accessed data in a register.编译器将始终尝试将最常访问的数据保存在寄存器中。 When a method/function is called, usually all register values are written back to RAM, unless the compiler can say for sure that the called function/method will not access the memory where the data came from.当一个方法/函数被调用时,通常所有的寄存器值都会被写回 RAM,除非编译器可以确定被调用的函数/方法不会访问数据来自的内存。 Also on return of a method/function it must write all register data back to RAM, otherwise the new values would be lost.同样在方法/函数返回时,它必须将所有寄存器数据写回 RAM,否则新值将丢失。 The return value itself is passed in a register on some CPU architectures, it is passed via stack otherwise.在某些 CPU 架构上,返回值本身在寄存器中传递,否则通过堆栈传递。

Variables in C++ are stored either on the stack or the heap. C++ 中的变量存储在堆栈或堆中。

stack:堆:

int x;

heap:堆:

int *p = new int;

That being said, both are structures built in RAM.话虽如此,两者都是内置于 RAM 中的结构。

If your RAM usage is high though windows can swap this out to disk.如果您的 RAM 使用率很高,尽管 Windows 可以将其交换到磁盘。

When computation is done on variables, the memory will be copied to registers.当对变量进行计算时,内存将被复制到寄存器。

C++ is not aware of your processor's cache. C++ 不知道您的处理器的缓存。

When you are running a program, written in C++ or any other language, your CPU will keep a copy of "popular" chunks of RAM in a cache.当您运行用 C++ 或任何其他语言编写的程序时,您的 CPU 将在缓存中保留一份“流行”RAM 块的副本。 That's done at the hardware level.这是在硬件级别完成的。

Don't think of CPU cache as "other" or "more" memory...it's just a mechanism to keep some chunks of RAM close by.不要将 CPU 缓存视为“其他”或“更多”内存……它只是一种将一些 RAM 块保持在附近的机制。

I think you are mixing up two concepts.我认为您混淆了两个概念。 One, how does the C++ language store variables in memory.一、C++语言如何在内存中存储变量。 Two, how does the computer and operating system manage that memory.二,计算机和操作系统如何管理该内存。

In C++, variables can be allocated on the stack, which is memory that is reserved for the program's use and is fixed in size at thread start or in dynamic memory which can be allocated on the fly using new.在 C++ 中,变量可以在堆栈上分配,堆栈是为程序使用而保留的内存,在线程启动时大小固定,或者在动态内存中,可以使用 new 动态分配。 A compiler can also choose to store the variables on registers in the processor if analysis of the code will allow it.如果代码分析允许,编译器还可以选择将变量存储在处理器的寄存器中。 Those variables would never see the system memory.这些变量永远不会看到系统内存。

If a variable ends up in memory, the OS and the processor chip set take over.如果变量在内存中结束,操作系统和处理器芯片组接管。 Both stack based addresses and dynamic addresses are virtual.基于堆栈的地址和动态地址都是虚拟的。 That means that they may or may not be resident in system memory at any given time.这意味着它们可能会或可能不会在任何给定时间驻留在系统内存中。 The in memory variable may be stored in the systems memory, paged onto disk or may be resident in a cache on or near the processor. in memory 变量可以存储在系统内存中,分页到磁盘上,或者可以驻留在处理器上或附近的缓存中。 So, it's hard to know where that data is actually living.因此,很难知道这些数据实际上在哪里。 If a program hasn't been idle for a time or two programs are competing for memory resources, the value can be saved off to disk in the page file and restored when it is the programs turn to run.如果一个程序有一段时间没有空闲或两个程序正在争夺内存资源,则可以将该值保存在页面文件中的磁盘中,并在程序运行时恢复。 If the variable is local to some work being done, it could be modified in the processors cache several times before it is finally flushed back to the system memory.如果该变量是正在完成的某些工作的本地变量,则可以在处理器缓存中对其进行多次修改,然后最终将其刷新回系统内存。 The code you wrote would never know this happened.您编写的代码永远不会知道发生了这种情况。 All it knows is that it has an address to operate on and all of the other systems take care of the rest.它只知道它有一个地址可以操作,所有其他系统负责其余的工作。

The C++ language supports two kinds of memory allocation through the variables in C++ programs: C++ 语言支持通过 C++ 程序中的变量进行两种内存分配:

Static allocation is what happens when you declare a static or global variable.静态分配是当您声明静态或全局变量时发生的情况。 Each static or global variable defines one block of space, of a fixed size.每个静态或全局变量定义一个固定大小的空间块。 The space is allocated once, when your program is started (part of the exec operation), and is never freed.该空间在您的程序启动时(exec 操作的一部分)分配一次,并且永远不会被释放。 Automatic allocation happens when you declare an automatic variable, such as a function argument or a local variable.当您声明一个自动变量(例如函数参数或局部变量)时,就会发生自动分配。 The space for an automatic variable is allocated when the compound statement containing the declaration is entered, and is freed when that compound statement is exited.自动变量的空间在包含声明的复合语句进入时分配,并在复合语句退出时释放。 The size of the automatic storage can be an expression that varies.自动存储的大小可以是变化的表达式。 In other CPP implementations, it must be a constant.在其他 CPP 实现中,它必须是一个常量。 A third important kind of memory allocation, dynamic allocation, is not supported by C++ variables but is available Library functions. C++ 变量不支持第三种重要的内存分配,动态分配,但可用的库函数。 Dynamic Memory Allocation动态内存分配

Dynamic memory allocation is a technique in which programs determine as they are running where to store some information.动态内存分配是一种技术,其中程序在运行时确定存储某些信息的位置。 You need dynamic allocation when the amount of memory you need, or how long you continue to need it, depends on factors that are not known before the program runs.当您需要的内存量或您继续需要多长时间取决于程序运行之前未知的因素时,您需要动态分配。

For example, you may need a block to store a line read from an input file;例如,您可能需要一个块来存储从输入文件中读取的行; since there is no limit to how long a line can be, you must allocate the memory dynamically and make it dynamically larger as you read more of the line.由于对一行的长度没有限制,因此您必须动态分配内存并在您阅读更多行时动态地使其变大。

Or, you may need a block for each record or each definition in the input data;或者,您可能需要为输入数据中的每个记录或每个定义一个块; since you can't know in advance how many there will be, you must allocate a new block for each record or definition as you read it.由于您无法预先知道会有多少,您必须在阅读时为每个记录或定义分配一个新块。

When you use dynamic allocation, the allocation of a block of memory is an action that the program requests explicitly.使用动态分配时,内存块的分配是程序显式请求的操作。 You call a function or macro when you want to allocate space, and specify the size with an argument.当您想分配空间时调用函数或宏,并用参数指定大小。 If you want to free the space, you do so by calling another function or macro.如果你想释放空间,你可以通过调用另一个函数或宏来实现。 You can do these things whenever you want, as often as you want.你可以随时随地做这些事情。

Dynamic allocation is not supported by CPP variables; CPP 变量不支持动态分配; there is no storage class “dynamic”, and there can never be a CPP variable whose value is stored in dynamically allocated space.没有“动态”存储类,永远不可能有一个 CPP 变量的值存储在动态分配的空间中。 The only way to get dynamically allocated memory is via a system call , and the only way to refer to dynamically allocated space is through a pointer.获得动态分配内存的唯一方法是通过系统调用,而引用动态分配空间的唯一方法是通过指针。 Because it is less convenient, and because the actual process of dynamic allocation requires more computation time, programmers generally use dynamic allocation only when neither static nor automatic allocation will serve.因为不太方便,而且动态分配的实际过程需要更多的计算时间,所以程序员一般只有在静态分配和自动分配都不会服务的情况下才使用动态分配。

For example, if you want to allocate dynamically some space to hold a struct foobar, you cannot declare a variable of type struct foobar whose contents are the dynamically allocated space.例如,如果要动态分配一些空间来保存结构体 foobar,则不能声明内容为动态分配空间的结构体 foobar 类型的变量。 But you can declare a variable of pointer type struct foobar * and assign it the address of the space.但是您可以声明一个指针类型的变量 struct foobar * 并为其分配空间的地址。 Then you can use the operators '*' and '->' on this pointer variable to refer to the contents of the space:然后你可以在这个指针变量上使用运算符 '*' 和 '->' 来引用空间的内容:

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

Variables can be held in a number of different places, sometimes in more than one place.变量可以保存在许多不同的地方,有时在多个地方。 Most variables are placed in RAM when a program is loaded;加载程序时,大多数变量都放在 RAM 中; sometimes variables which are declared const are instead placed in ROM.有时声明为const变量被放置在 ROM 中。 Whenever a variable is accessed, if it is not in the processor's cache, a cache miss will result, and the processor will stall while the variable is copied from RAM/ROM into the cache.每当访问变量时,如果它不在处理器的高速缓存中,就会导致高速缓存未命中,并且处理器将在变量从 RAM/ROM 复制到高速缓存时停顿。

If you have any halfway decent optimizing compiler, local variables will often instead be stored in a processor's register file.如果您有任何不错的优化编译器,则局部变量通常会存储在处理器的寄存器文件中。 Variables will move back and forth between RAM, the cache, and the register file as they are read and written, but they will generally always have a copy in RAM/ROM, unless the compiler decides that's not necessary.变量将在读取和写入时在 RAM、缓存和寄存器文件之间来回移动,但它们通常始终在 RAM/ROM 中具有副本,除非编译器决定不需要这样做。

depending on how they are declared, they will either be stored in the " heap " or the " stack "根据它们的声明方式,它们将存储在“”或“堆栈”中

The heap is a dynamic data structure that the application can use.堆是应用程序可以使用的动态数据结构。

When the application uses data it has to be moved to the CPU's registers right before they are consumed, however this is very volatile and temporary storage.当应用程序使用数据时,必须在它们被消耗之前将其移动到 CPU 的寄存器,但是这是非常易失的临时存储。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM