关于C里的内存分配问题,网上版本不一,个人总结了一下,有问题请指正。
内存从上到下最开始是栈区:总是说堆栈,但堆和栈是两个完全不同的结构,栈区的数据存储与别的区不同是由上到下存储的,最开始进栈的地址最高,依次向下递减。栈区存储的主要是局部变量,它具有先进后出的特性,最先进来的数据要到最后才能取出来,我们在函数调用的时候,第一个进栈的是调用函数里被调用函数的下一条语句的初始地址,然后是调用函数的形式参数(函数调用的实参会被计算机存储在形式参数的存储区里),然后是函数里的各个局部变量,静态局部变量不入栈,它会存储在数据区(之后讲),在该函数执行结束的时候,再依次将局部变量,形式参数全部释放掉,这是栈的指针指向的是当初第一个进栈的调用函数的下一条语句,函数会继续从此继续执行。alloca()函数用来在栈中分配size个字节的内存空间,因此函数返回时会自动释放掉空间。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
栈区下方是堆区。不同于栈区的内存分配是静态分配方式,即由计算机自动分配的,程序员无需过问,系统会自动为每一个值分配一个空间,而堆区是动态分配方式,即为了代码灵活性,由程序员自己设定的存储区。另一点不同于栈区的是,栈区像一个箱子,第一个放进去的要等到它上面的全部移走才能出来,而堆区像一个书架,虽然数据量也很大,但是可以随意放置并拿出自己想要的那本书。堆区分配地址用函数p=malloc (byte),返回值为分配的内存首地址 ,首先要知道操作系统有一个记录堆区空闲内存地址的链表,当程序员用malloc(byte)发出这个内存申请时,系统会根据这个链表,寻找第一个连续空闲内存大于byte的堆节点,并将这个堆节点从链表上删除。由于往往寻找到的空闲内存大小是大于byte的,系统还要将多余的那部分空闲内存的堆节点记录到链表中,因此用堆分配内存速度比较慢,而且容易产生大量的碎片,但是很灵活方便。一般分配好内存之后要用memset函数将该内存里的数据重新赋值,用 法: void *memset(void *p, char ch, unsigned n),将p指向的内存从上到下共n个字节赋值为ch,一般可赋值为0.注意内存使用结束之后要用free(p)将该内存释放掉,否则可能造成内存泄漏,一部分的内存没有被使用,但是由于没有free,因此系统认为这部分内存还在使用,造成不断的向系统申请内存,使得系统可用内存不断减少.但是,内存泄漏仅仅指程序在运行时,程序退出时,OS将回收所有的资源.可以重启一下程序。
堆区下方是数据段。包括BBS(全局未初始化数据)以及全局变量/静态局部变量/常量数据(字符串)。由于这些数据在整个程序运行期间都可能用到,所以单独拿出来。
最下方是代码段。即存放函数体的二进制代码。
来看一个网上很流行的经典例子:main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456\0在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10); 堆
p2 = (char *)malloc(20); 堆
free(p1);
free(p2);
}