C++ 当计算机程序运行时会发生什么?

C++ 当计算机程序运行时会发生什么?,c++,memory,operating-system,x86,computer-architecture,C++,Memory,Operating System,X86,Computer Architecture,我知道一般的理论,但我不知道细节 我知道一个程序驻留在计算机的辅助存储器中。一旦程序开始执行,它就被完全复制到RAM中。然后处理器一次检索几个指令(取决于总线的大小),将它们放入寄存器并执行 我还知道计算机程序使用两种内存:堆栈和堆,它们也是计算机主内存的一部分。堆栈用于非动态内存,堆用于动态内存(例如,与C++中的new运算符相关的所有内容) 我不明白的是这两件事是如何联系在一起的。堆栈在什么时候用于执行指令?指令从RAM到堆栈再到寄存器?这实际上取决于系统,但现代操作系统倾向于加载进程映像并

我知道一般的理论,但我不知道细节

我知道一个程序驻留在计算机的辅助存储器中。一旦程序开始执行,它就被完全复制到RAM中。然后处理器一次检索几个指令(取决于总线的大小),将它们放入寄存器并执行

我还知道计算机程序使用两种内存:堆栈和堆,它们也是计算机主内存的一部分。堆栈用于非动态内存,堆用于动态内存(例如,与C++中的
new
运算符相关的所有内容)


我不明白的是这两件事是如何联系在一起的。堆栈在什么时候用于执行指令?指令从RAM到堆栈再到寄存器?

这实际上取决于系统,但现代操作系统倾向于加载进程映像并分配内存,如下所示:

+---------+
|  stack  |  function-local variables, return addresses, return values, etc.
|         |  often grows downward, commonly accessed via "push" and "pop" (but can be
|         |  accessed randomly, as well; disassemble a program to see)
+---------+
| shared  |  mapped shared libraries (C libraries, math libs, etc.)
|  libs   |
+---------+
|  hole   |  unused memory allocated between the heap and stack "chunks", spans the
|         |  difference between your max and min memory, minus the other totals
+---------+
|  heap   |  dynamic, random-access storage, allocated with 'malloc' and the like.
+---------+
|   bss   |  Uninitialized global variables; must be in read-write memory area
+---------+
|  data   |  data segment, for globals and static variables that are initialized
|         |  (can further be split up into read-only and read-write areas, with
|         |  read-only areas being stored elsewhere in ROM on some systems)
+---------+
|  text   |  program code, this is the actual executable code that is running.
+---------+
int mul( int x, int y ) {
    return x * y;       // this stores the result of MULtiplying the two variables 
                        // from the stack into the return value address previously 
                        // allocated, then issues a RET, which resets the stack frame
                        // based on the arg list, and returns to the address set by
                        // the CALLer.
}

int main() {
    int x = 2, y = 3;   // these variables are stored on the stack
    mul( x, y );        // this pushes y onto the stack, then x, then a return address,
                        // allocates space on the stack for a return value, 
                        // then issues an assembly CALL instruction.
}
这是许多常见虚拟内存系统上的通用进程地址空间。“洞”是总内存的大小,减去所有其他区域占用的空间;这为堆的成长提供了很大的空间。这也是“虚拟的”,意味着它通过翻译表映射到您的实际内存,并且可能实际存储在实际内存中的任何位置。这样做是为了保护一个进程不访问另一个进程的内存,并使每个进程都认为它在一个完整的系统上运行

请注意,在某些系统上,例如堆栈和堆的位置的顺序可能不同(有关Win32的更多详细信息,请参阅下文)

其他系统可能非常不同。例如,DOS运行时,其内存分配与运行程序时的情况大不相同:

+-----------+ top of memory
| extended  | above the high memory area, and up to your total memory; needed drivers to
|           | be able to access it.
+-----------+ 0x110000
|  high     | just over 1MB->1MB+64KB, used by 286s and above.
+-----------+ 0x100000
|  upper    | upper memory area, from 640kb->1MB, had mapped memory for video devices, the
|           | DOS "transient" area, etc. some was often free, and could be used for drivers
+-----------+ 0xA0000
| USER PROC | user process address space, from the end of DOS up to 640KB
+-----------+
|command.com| DOS command interpreter
+-----------+ 
|    DOS    | DOS permanent area, kept as small as possible, provided routines for display,
|  kernel   | *basic* hardware access, etc.
+-----------+ 0x600
| BIOS data | BIOS data area, contained simple hardware descriptions, etc.
+-----------+ 0x400
| interrupt | the interrupt vector table, starting from 0 and going to 1k, contained 
|  vector   | the addresses of routines called when interrupts occurred.  e.g.
|  table    | interrupt 0x21 checked the address at 0x21*4 and far-jumped to that 
|           | location to service the interrupt.
+-----------+ 0x0
您可以看到,DOS允许直接访问操作系统内存,没有任何保护,这意味着用户空间程序通常可以直接访问或覆盖他们喜欢的任何内容

然而,在进程地址空间中,程序看起来很相似,只是它们被描述为代码段、数据段、堆、堆栈段等,并且映射方式略有不同。但大部分一般区域仍然存在

在将程序和必要的共享lib加载到内存中,并将程序的各个部分分配到正确的区域后,操作系统开始在其主方法所在的位置执行您的进程,并且您的程序从那里接管,在需要时进行必要的系统调用

不同的系统(嵌入式,无论什么)可能有非常不同的体系结构,例如无堆栈系统、哈佛体系结构系统(代码和数据保存在单独的物理内存中)、实际上将BSS保存在只读内存中的系统(最初由程序员设置)等等。但这是一般要点


你说:

我还知道计算机程序使用两种内存:堆栈和堆,它们也是计算机主内存的一部分

“堆栈”和“堆”只是抽象概念,而不是(必然)物理上不同的内存“种类”

A仅仅是后进先出的数据结构。在x86体系结构中,实际上可以通过使用末端的偏移量来随机寻址,但最常见的功能是PUSH和POP,分别从中添加和删除项。它通常用于函数局部变量(所谓的“自动存储”)、函数参数、返回地址等(详见下文)

A只是一块内存的昵称,可以按需分配,并随机寻址(也就是说,您可以直接访问其中的任何位置)。它通常用于运行时分配的数据结构(在C++中,使用<代码>新< /COD>和<代码>删除<代码>,以及<代码> Malc C <代码>和C中的朋友)。 x86体系结构上的堆栈和堆物理上驻留在系统内存(RAM)中,并通过虚拟内存分配映射到进程地址空间,如上所述

(仍在x86上)物理上驻留在处理器内部(与RAM相反),由处理器从文本区域加载(也可以从内存中的其他位置或其他位置加载,具体取决于实际执行的CPU指令)。它们基本上只是非常小、非常快的片上内存位置,用于许多不同的用途

寄存器布局高度依赖于体系结构(事实上,寄存器、指令集和内存布局/设计正是“体系结构”的含义),因此我不在此详述,但建议您学习汇编语言课程,以便更好地理解它们


你的问题:

堆栈在什么时候用于执行指令?指令从RAM到堆栈再到寄存器

堆栈(在拥有和使用它们的系统/语言中)最常用的用法如下:

+---------+
|  stack  |  function-local variables, return addresses, return values, etc.
|         |  often grows downward, commonly accessed via "push" and "pop" (but can be
|         |  accessed randomly, as well; disassemble a program to see)
+---------+
| shared  |  mapped shared libraries (C libraries, math libs, etc.)
|  libs   |
+---------+
|  hole   |  unused memory allocated between the heap and stack "chunks", spans the
|         |  difference between your max and min memory, minus the other totals
+---------+
|  heap   |  dynamic, random-access storage, allocated with 'malloc' and the like.
+---------+
|   bss   |  Uninitialized global variables; must be in read-write memory area
+---------+
|  data   |  data segment, for globals and static variables that are initialized
|         |  (can further be split up into read-only and read-write areas, with
|         |  read-only areas being stored elsewhere in ROM on some systems)
+---------+
|  text   |  program code, this is the actual executable code that is running.
+---------+
int mul( int x, int y ) {
    return x * y;       // this stores the result of MULtiplying the two variables 
                        // from the stack into the return value address previously 
                        // allocated, then issues a RET, which resets the stack frame
                        // based on the arg list, and returns to the address set by
                        // the CALLer.
}

int main() {
    int x = 2, y = 3;   // these variables are stored on the stack
    mul( x, y );        // this pushes y onto the stack, then x, then a return address,
                        // allocates space on the stack for a return value, 
                        // then issues an assembly CALL instruction.
}
编写这样一个简单的程序,然后将其编译成汇编(
gcc-sfoo.c
,如果您有权访问gcc),然后看一看。这个组件很容易理解。您可以看到,堆栈用于函数局部变量以及调用函数、存储其参数和返回值。这也是为什么当您执行以下操作时:

f( g( h( i ) ) ); 
所有这些都会依次调用。它实际上是建立一个函数调用和它们的参数堆栈,执行它们,然后在返回(或向上;)时弹出它们。但是,如上所述,堆栈(在x86上)实际上驻留在进程内存空间(在虚拟内存中),因此可以直接对其进行操作;在执行过程中,它不是一个单独的步骤(或者至少与流程正交)

Fy,以上是,C++也使用的。其他语言/系统可能会将参数推送到堆栈i上

DMUL