内存五大模块
一、 在c中分为这几个存储区
内存区域 | 存放内容(elf存放区域) | 释放时间 |
---|---|---|
栈 | 在函数体中定义的变量通常是在栈上(栈) | 由编译器自动分配释放 |
堆 | 用malloc, calloc, realloc等分配内存的函数分配得到的就是在堆上(堆) | 一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收 |
全局区(静态区) | 全局变量和静态变量的存储是放在一块的。初始化的全局变量和静态变量在一块区域(data段),未初始化的全局变量和未初始化的静态变量在相邻的另一块区域(bss段)。 | 程序结束释放 |
常量区域 | 函数中的"adgfdf"这样的字符串存放在常量区(text段) | 程序结束释放 |
程序代码区 | 存放二进制代码(text段) | / |
注意:在所有函数体外定义的是全局量,加了static修饰符后不管在哪里都存放在全局区(静态区),在所有函数体外定义的static变量表示在该文件中有效,不能extern到别的文件用,在函数体内定义的static表示只在该函数体内有效。
int a = 0; //全局初始化区
char *p1; //全局未初始化区
void main() {
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; / /123456{post.content}在常量区,p3在栈上
static int c = 0; //全局(静态)初始化区
p1 = (char *)malloc(10); //分配得来得10字节的区域在堆区
p2 = (char *)malloc(20); //分配得来得20字节的区域在堆区
strcpy(p1, "123456"); //123456{post.content}放在常量区,编译器可能会将它与p3所指向的"123456"优化成一块
}
堆栈基本对比
堆 | 栈 |
---|---|
是系统提供的功能,特点是快速高效,缺点是有限制,数据不灵活 | 是函数库提供的功能,特点是灵活方便,数据适应面广泛,但是效率有一定降低 |
栈是系统数据结构,对于进程/线程是唯一的 | 堆是函数库内部数据结构,不一定唯一;不同堆分配的内存无法互相操作; |
栈空间分静态分配和动态分配两种。静态分配是编译器完成的,比如自动变量(auto)的分配。动态分配由alloca函数完成。栈的动态分配无需释放(是自动的),也就没有释放函数。为可移植的程序起见,栈的动态分配操作是不被鼓励的 | 堆空间的分配总是动态的,虽然程序结束时所有的数据空间都会被释放回系统,但是精确的申请内存 |
- 堆栈 - 在释放内存方面的对比
、 | 堆 | 栈 |
---|---|---|
碎片问题 | 对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低 | 对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出 |
生长方向 | 生长方向是向上的,也就是向着内存地址增加的方向 | 生长方向是向下的,是向着内存地址减小的方向增长 |
分配方式 | 堆都是动态分配的,没有静态分配的堆 | 栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现 |
分配效率 | 栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高 | 堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多 |