【问题标题】:Does memory allocation and initialisation take place separatelty during compile time and runtime?内存分配和初始化是否在编译时和运行时分开进行?
【发布时间】:2019-05-31 14:56:45
【问题描述】:
当我们声明一个变量时,比如一个 int,我想知道在内存分配和初始化过程中涉及的步骤。还有一个指针
int x = 5;
现在在编译期间,4 字节被分配给整数 x。但是内存什么时候被值 5 填满呢?初始化是否发生在编译或运行时执行期间。
同样,考虑
int x = 5;
int* p = &x;
在这两行中,分配和初始化的过程是什么。
【问题讨论】:
标签:
memory
memory-management
runtime
dynamic-memory-allocation
compile-time
【解决方案1】:
变量初始化取决于变量的种类。全局或静态变量在编译时初始化,而自动变量在运行时完全管理。
全局变量
在编译时,所有全局变量的值都是已知的。这些值由编译器写入目标文件的特定部分。
在链接时,会收集所有目标文件并确定每个变量的内存位置。这允许知道每个变量的地址,以防这些地址之一被分配给另一个变量。
结果,会生成一个可执行文件,其中包含每个部分(文本、数据、rodata 等)内容的描述。在 data 或 rodata 部分,写入所有初始化的全局变量的值。
在运行时,加载程序读取不同部分的描述并询问操作系统内存。然后它将所有部分的内容复制到各自的内存位置。
这是使用在编译或链接时确定的值初始化变量的方式。
唯一的例外是初始化为零(或未初始化)的变量。它们位于一个特殊的部分(通常称为 bss)。为了减小可执行文件的大小,这些零值不会写入可执行文件中。相反,在执行main() 之前,运行时过程会将 bss 部分的所有内容都设置为零。
自动变量
程序完全不同。在程序运行之前不知道这些变量的位置,唯一的方法是通过机器指令计算它们的值。
所以编译器首先判断这些变量是在寄存器还是内存中,当进入函数时,第一条指令是为局部变量保留堆栈空间并初始化它们的值。这是通过常规机器指令完成的。
如果值是另一个变量的地址(比如 y=&x),
* 如果 x 是本地(自动)变量,则地址将通过写入 y 堆栈指针寄存器的内容和编译器确定的给定偏移量之和来计算
* 如果 x 是全局变量或静态变量,则在链接时,一旦全局变量的地址已知,链接器就会修改编译器生成的指令,将正确的地址写入用于表示y 的寄存器或堆栈位置。
【解决方案2】:
在某些情况下无法在运行时定义:
如果 user_input == “是”:
我的变量 = 5
别的:
my_var = 7
但通常这取决于负责的编译器程序员已经实现的概念。如果您使用不同的编译器或不同的语言,那么情况可能会有所不同。