在c++中内存主要分为5个存储区:html
栈(Stack):局部变量,函数参数等存储在该区,由编译器自动分配和释放.栈属于计算机系统的数据结构,进栈出栈有相应的计算机指令支持,并且分配专门的寄存器存储栈的地址,效率分高,内存空间是连续的,但栈的内存空间有限。c++
堆(Heap):须要程序员手动分配和释放(new,delete),属于动态分配方式。内存空间几乎没有限制,内存空间不连续,所以会产生内存碎片。操做系统有一个记录空间内存的链表,当收到内存申请时遍历链表,找到第一个空间大于申请空间的堆节点,将该节点分配给程序,并将该节点从链表中删除。通常,系统会在该内存空间的首地址处记录本次分配的内存大小,用于delete释放该内存空间。程序员
全局/静态存储区:全局变量,静态变量分配到该区,到程序结束时自动释放,包括DATA段(全局初始化区)与BBS段(全局未初始化段)。其中,初始化的全局变量和静态变量存放在DATA段,未初始化的全局变量和静态变量存放在BBS段。BBS段特色:在程序执行前BBS段自动清零,因此未初始化的全局变量和静态变量在程序执行前已经成为0.算法
文字常量区:存放常量,并且不容许修改。程序结束后由系统释放。数组
程序代码区:存放程序的二进制代码数据结构
使用存储区的三种方式:
1)静态存储区(Static Memory)tcp
全局变量,静态变量及静态类成员存储在该区,在编译期间就进行分配,生存期到程序结束。存储在该区的对象只初始化一次,且在程序运行期间地址固定不变。函数
2)自动存储区(Autormatic Memory)spa
局部变量,函数参数等存储在该区,由编译器自动分配和释放操作系统
3)自由存储区(Free Store)
由程序员手动分配和释放内存(new,delete)
堆和栈的区别:
1)空间大小:栈的内存空间是连续的,空间大小一般是系统预先规定好的,即栈顶地址和最大空间是肯定的;而堆得内存空间是不连续的,由一个记录空间空间的链表负责管理,所以内存空间几乎没有限制,在32位系统下,内存空间大小可达到4G
2)管理方式:栈由编译器自动分配和释放,而堆须要程序员来手动分配和释放,若忘记delete,容易产生内存泄漏。
3)生长方向不一样:对于栈,他是向着内存地址减少的方向生长的,这也是为何栈的内存空间是有限的;而堆是向着内存地址增大的方向生长的
4)碎片问题:因为栈的内存空间是连续的,先进后出的方式保证不会产生零碎的空间;而堆分配方式是每次在空闲链表中遍历到第一个大于申请空间的节点,每次分配的空间大小通常不会正好等于申请的内存大小,频繁的new操做势必会产生大量的空间碎片
5)分配效率:栈属于机器系统提供的数据结构,计算机会在底层对栈提供支持,出栈进栈由专门的指令执行,所以效率较高。而堆是c/c++函数库提供的,当申请空间时须要按照必定的算法搜索足够大小的内存空间,当没有足够的空间时,还须要额外的处理,所以效率较低。
使用内存时几点注意事项:
1)用new和malloc申请内存时,在使用前要检查内存是否分配成功
char *p=new char[10]; if(p==NULL) return;
2)使用内存以前要进行初始化
3)在对内存进行操做时,防止越界,如数组操做要注意下标范围
4)对于动态分配的内存,必定要手动释放,不然程序每运行一次就会丢失一部份内存,形成内存泄漏
5)防止内存释放后继续使用它,主要有如下三种状况:
a.程序中的对象调用关系过于复杂,实在难以搞清楚某个对象到底是否已经释放了内存,此时应该从新设计数据结构,从根本上解决对象管理的混乱局面。
b.函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,由于该内存在函数体结束时被自动销毁。
c.使用free或delete释放了内存后,没有将指针设置为NULL。致使产生“野指针”。
野指针:“野指针”不是NULL指针,是指向“垃圾”内存的指针。人们通常不会错用NULL指针,由于用if语句很容易判断。可是“野指针”是很危险的,if语句对它不起做用。
“野指针”的成因主要有三种:
(a)指针变量没有被初始化。任何指针变量刚被建立时不会自动成为NULL指针,它的缺省值是随机的,它会乱指一气。因此,指针变量在建立的同时应当被初始化,要么将指针设置为NULL,要么让它指向合法的内存。
char *p; //此时p为野指针
(b)指针p被free或者delete以后,没有置为NULL,让人误觉得p是个合法的指针.
char *p=new char[10]; //指向堆中分配的内存首地址 cin>> p; delete []p; //p从新变为野指针
(c)指针操做超越了变量的做用范围。
char *p=new char[10]; //指向堆中分配的内存首地址 cin>> p; cout<<*(p+10); //可能输出未知数据
6)指针的注意点:
a.指针指向常量存储区对象
char *p="abc";
此时p指向的是一个字符串常量,不能对*p的内容进行写操做,如srtcpy(p,s)是错误的,由于p的内容为“abc”字符串常量,该数据存储在常量存储区,但能够对指针p进行操做,让其指向其余的内存空间。
b.资源泄漏
char *p=new char[3]; //分配三个字符空间,p指向该内存空间
p="ab"; //此时p指向常量“ab”,而再也不是new char分配的内存空间了,从而形成了资源泄漏
delete []p; //释放时报错
c.内存越界
char *p=new char[3]; //分配三个字符空间,p指向该内存空间
strcpy(p,"abcd"); //将abcd存处在分配的内存空间中,因为strlen("abcd")=4>3,越界
delete []p; //释放时出错
注:p="ab"和strcpy(p,"ab"),含义不同,前者指针p指向常量“ab”存储区域的首地址,改变了p最开始指向的new申请的内存空间;然后者是将“ab”分配到new申请的内存空间中;