程序内存布局是理解软件本质的基础要素。支持一个程序运行的所有内存大体可分为以下几部分,或者说程序运行需要系统为其提供如下几部分存储区域:
栈:由编译器自动分配释放,存放函数参数,局部变量等,特点为后进先出。
堆:程序员调用malloc/free进行内存动态分配和释放所操作的内存区域。
全局数据区(静态区):全局变量以及static变量存放的内存区,注意static变量不管在哪里定义都存放在全局数据区(见C基础static篇)。初始化的全局和静态变量在全局初始化区,未初始化的全局和静态变量在全局未初始化区。整个全局数据区在程序结束后由系统释放。
程序代码区:存放二进制的程序代码,一般规定为只读。
常量区:里面存放常量,不能修改,如"adgf"这样的字符串就存放在常量区,一直占用到程序结束。
不同编译器和系统的内存布局划分会有细小差别,但上述几大块基本跑不掉。它们是组成一个完整程序的内存基础,这里的程序指运行在没有OS的裸系统上的控制程序,比如单片机应用等,而引入OS后,单个进程所包含的元素也基本归于以上几类。下面举例说明C程序中不同元素在内存中的定位区域:
int a = 0; //全局初始化区
char *p1; //全局未初始化区
void main()
{
int b; //栈
char s[] = "abc"; //s[]在栈上,abc在常量区
char *p2; //栈
char *p3 = "12345"; // p3在栈上,12345在常量区。
static int c =0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20); //分配的10和20字节内存块在堆里,而p1,p2本身在栈中
strcpy(p1,"12345"); //12345在常量区,编译器会将它与p3所指的"12345"优化成一块
}
总结:函数体中定义的局部变量(非static)位于栈上;通过malloc,calloc等函数分配所得到的内存在堆上;所有全局变量以及static静态变量都放在全局数据区。程序自身指令位于只读代码区。常量位于常量区(有的也散列在代码区,因为都是只读属性,可以合并放在一起)。