1、所谓在编译期间分配空间指的是静态分配空间(相对于用new动态申请空间),如全局变量或静态变量(包括一些复杂类型的
常量),它们所需要的空间大小可以明确计算出来,并且不会再改变,因此它们可以直接存放在可执行文件的特定的节里(而且
包含初始化的值),程序运行时也是直接将这个节加载到特定的段中,不必在程序运行期间用额外的代码来产生这些变量。
其实在运行期间再看“变量”这个概念就不再具备编译期间那么多的属性了(诸如名称,类型,作用域,生存期等等),对应的
只是一块内存(只有首址和大小), 所以在运行期间动态申请的空间,是需要额外的代码维护,以确保不同变量不会混用内存。
比如写new表示有一块内存已经被占用了,其它变量就不能再用它了; 写delete表示这块内存自由了,可以被其它变量使用了。
(通常我们都是通过变量来使用内存的,就编码而言变量是给内存块起了个名字,用以区分彼此)
内存申请和释放时机很重要,过早会丢失数据,过迟会耗费内存。特定情况下编译器可以帮我们完成这项复杂的工作(增加额外
的代码维护内存空间,实现申请和释放)。从这个意义上讲,局部自动变量也是由编译器负责分配空间的。进一步讲,内存管理
用到了我们常常挂在嘴边的堆和栈这两种数据结构。
最后对于“编译器分配空间”这种不严谨的说法,你可以理解成编译期间它为你规划好了这些变量的内存使用方案,这个方案写
到可执行文件里面了(该文件中包含若干并非出自你大脑衍生的代码),直到程序运行时才真正拿出来执行。
2、编译其实只是一个扫描过程,进行词法语法检查,代码优化而已。我想你说的“编译时分配内存”是指“编译时赋初值”,它只是形成一个文本,检查无错误,并没有分配内存空间。
当你运行时,系统才把程序导入内存。一个进程(即运行中的程序)在主要包括以下五个分区:
栈区、堆区、全局数据区/静态区、代码区、常量区
- 栈区用来存放局部数据或者是函数的参数,函数的返回值之类的变量(其中还有返回到调用函数下一条指令的地址)
- 堆区用来存放程序中动态申请内存的变量
- 全局变量/静态区用来存放程序中的全局变量或者是静态变量,因为它们的大小是确定的,在编译期间就已经进行静态空间的分配,而且不会改变,这样会提高程序对这些数据的访问速度
- 代码区(code)用来存放编译后的二进制代码
- 常量区用来存放我们声明的常量(const类型)
代码(编译后的二进制代码)放在code区,代码中生成的各种变量、常量按不同类型分别存放在其它四个区。系统依照代码顺序
执行,然后依照代码方案改变或调用数据,这就是一个程序的运行过程。
3、
编译时分配内存
---------------
编译时是不分配内存的。此时只是根据声明时的类型进行占位,到以后程序执行时分配内存才会正确。所以声明是给编译器看的
,聪明的编译器能根据声明帮你识别错误。
运行时分配内存
---------------
这是对的,运行时程序是必须调到“内存”的。因为CPU(其中有多个寄存器)只与内存打交道的。程序在进入实际内存之前要首
先分配物理内存。
编译过程
---------------
当执行这个EXE文件以后,此程序就被加载到内存中,成为进程。此时一开始程序会初始化一些全局对象,然后找到入口函数
,就开始按程序的执行语句开始执行。此时需要的内存只能在程序的堆上进行动态增加/释放了。