linux系统下,程序是一个可执行文件,通常是ELF格式。通常,linux的可执行文件拥有两种内存分配方式:存储时 和 运行时
1、存储时
看实例,下面是对可执行文件aa运行size命令后得到的结果。
[root@xxx1 algriom]# size aaPS:第4列和第5列是分别以十进制和十六进制表示的三个段的总长度。
2、运行时(进程结构)
运行时是指一个正在运行的进程在内存空间中的结构,也就是一个进程的结构。
一般包括代码区、全局存储区(初始化数据区DATA、未初始化数据区BBS)、文字常量区、堆和栈5个部分。
(1)代码区:存放函数体的二进制代码
(2)全局(静态)存储区:存放全局变量、静态变量;
DATA:存放初始化的全局变量和静态变量static
BBS:存放未初始化的全局变量和静态变量static,BBS段中,内存中所有字节默认值都是0;
【C中static作用】:1、隐藏;2、默认初始化为0,只能赋一次初值;3、保持局部变量内容持久
(3)文字常量区(只读区):常量字符串;const修饰的全局变量保存在文本段中,const修饰的局部变量保存在栈中。
但是,数组只存放于栈、全局存储区
(4)栈区:存储函数参数值、返回值、局部变量等。向下生长。
(5)堆区:用于动态内存分配。向上生长。函数结束变量就消失。可以跨函数使用,直到free时才释放
int main() { char a[] = "hello"; char *p = "hello!"; printf("_______%d\n",sizeof(a)); printf("_______%d\n",sizeof(p)); Test(); system("pause"); return 0; }答案:6,4
分析:p指针存储在栈,而其存储的hello!存在文字常量区;
a[] 数组存放在栈,此时的hello不仅仅存放在文字常量区,还拷贝一份存放在栈中,因为a是一个存放在栈上的数组。
堆区和栈区的区别如下:
(1)栈由操作系统自动管理,无需程序员手工控制,而堆区的申请和释放工作由程序员控制。一般由malloc(或new)函数来分配内存块,并且需要用free(delete)函数释放内存。如果程序员没有释放掉,那么就会出现常说的内存泄漏问题。需要注意的是,两个紧挨着定义的指针变量,所指向的malloc出来的两块内存并不一定的是紧挨着的,所以会产生内存碎片。
栈 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
(2)栈是一块连续的内存区域,由系统预先设定,一般较小,从高地址向低地址增长;而堆是向高地址扩展的数据结构,是不连续的内存区域,空间较大。另外,分配的效率上,栈的分配比堆的分配要高效很多。
注意:
1、 初始化的全局变量和静态变量保存在data中。
2、 未经初始化的全局变量和静态变量保存在BSS中。
3、 函数内部声明的局部变量保存在栈中。
4、 const修饰的全局变量保存在文本段中,const修饰的局部变量保存在栈中。
5、 字符串常量保存在文本段中。
3、例子程序
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
}strcpy(p1, "123456"); 123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。