需要知道的概念:
1、程序:包括代码和数据,是静态的概念
2、进程:程序的执行过程,是指一个程序中的代码在一个数据集合中的运行过程,所以说相同代码在不同的数据集合上运行,乃至在同样的数据集合上的多次运行都是不同的进程。进程是一个动态概念
3、线程:可以理解为进程中的一个代码片段的执行。故常说一个进程包含多个线程,多个线程共享数据空间。操作系统不会单独为线程分配资源(存储空间)
程序是静态的,进程是动态的;进程是操作系统分配资源的最小单位,线程是操作系统调度的最小单位。
一个程序在运行起来以后,就成为的进程,此时操作系统要为该进程分配虚拟存储空间,这个存储空间就包括了:栈区(stack),堆区(heap),全局区(静态区)(static),文字常量区,代码区。至于这些存储区的使用情况,就取决于我们程序员的代码实现了!举例说明:
栈区(stack):人们说:栈区是由编译器自动分配的,我认为这种说法是不准确的,只是说在编译阶段,栈区的分配情况就已经是确定好了的(也就是不管进程的接收参数如何,或是执行多少次,栈区变量一定是那样一个地址),毕竟内存的分配是由操作系统内核的内存管理机制来完成的。OK!不钻牛角,就说是编译器在编译时分配。我的理解是:在编译阶段,编译器会根据代码中变量的定义情况,依据字节对齐原理进行分配(具体方法会在后续的《栈区内存分配详解》中介绍)。但要注意,进程的执行进入函数体以后(自动变量所在的函数体),变量才和栈区地址对应起来了,这时&a(a是一个栈区变量)才是有值的,但这个时候变量不能使用,其值可能是一个不确定数。当程序运行到达该变量的定义语句时,作用域开始,并且变量中有了确定的值,当函数体结束,作用域结束,空间有操作系统回收。
堆区(heap):堆区是由程序员分配释放的。我的理解是:堆区是进程执行过程中,由操作系统根据进程的运行情况,动态分配的;释放和回收需要程序员写代码来实现,而不是自动回收。
这就解释了为什么,int a[n]--这样的栈区数组定义方式有错,因为在编译阶段,程序没有运行,故不知道变量n的值为多少,所以产生错误!!而动态分配的存储空间就可以这样定义 int *p = new a[n],因为动态分配存储空间是堆上分配,属于运行时分配,程序运行到动态分配存储空间这条语句时,n的值已经计算出来了。而且不同的运行过程,或是多次执行,n的值可能不一样(例如进程的接收参数不同),也就是空间大小也就不一样,操作系统需要在堆区二叉树中寻找一个满足该大小的空间,所以起始地址也会不一样。再次印证了动态的含义。
全局(静态)区:1.全局变量:编译阶段 由编译器分配(确定)地址,但是在进程开始时才与该地址对应,但此时变量有一不确定值,处于不可使用状态,一直到改全局变量的定义语句,作用域开始,一直到进程结束。2.static静态变量:在整个进程过程中,只能被赋初值一次。
文字常量区:用于存放常量字符串。
代码区:存放程序的二进制代码。
示例:
1 #include2 using namespace std; 3 4 int a = 0; /*全局区*/ 5 char *p; /*全局区*/ 6 7 int main(void) 8 { 9 int b = 10; /*栈区*/10 char s[] = "abc"; /*abc在常量区,s在栈区*/11 char *p1; /*栈区*/12 13 static int c = 0; /*全局(静态区)*/14 15 p = (char*)malloc(b); /*变量p在全局区,指向的分配得来的b个存储空间在堆区*/16 p1 = new char[b]; /*变量p1在栈区,指向的分配得来的b个存储空间在堆区*/17 return 0;18 }