分享

c++基础6:堆和栈 内存泄漏 栈溢出

 天海544 2014-03-11

一.首先讲解一下程序中的数据在内存中的存放方式有以下几种:

1.栈(也可以成为堆栈)区:由编译器自动分配并且释放,该区域一般存放函数的参数值,局部变量值等,当函数运行结束并且返回时,所有的函数参数和局部变量都会被操作系统自动回收。

2.堆区:一般由程序员分配及释放,若程序员不释放,程序结束时可能由操作系统自动回收。

3.寄存器区:用来保存栈顶指针和指令指针

4.全局(静态)区:全局变量和静态变量是存储在一块的。初始化的全局变量和静态变量在一块区域,未初始化的全局变量和静态变量在相邻的另一块区域。程序结束后由系统释放。

5.文字常量区:存放常量字符串,程序结束后由系统释放。

6.程序代码区:存放函数体的二进制代码。

 

二.堆和栈的不同点

 

内存申请和释放方式上的不同

由系统自动分配,例如声明一个局部变量int a;那么系统就会自动在栈中为变量a开辟内存空间,函数结束时变量a占的空间会被系统自动回收

需要程序员自己申请,因此也需要指明变量大小。例如使用new操作符申请:int *a=new int;那么系统就会在堆区分配一个大小为4Byte的内存空间。

使用delete操作符释放:delete a;这样就释放了在堆区分配的空间

系统响应的不同

只有在栈的空间大于申请的空间,系统才会为程序提供内存,否则将会提示overflow,也就是栈溢出(申请空间大于栈空间)

操作系统中有一个记录空闲内存地址的链表,当我们在堆上申请空间后,将在空闲链表中找到符合申请大小的空间节点,该节点会被系统从链表中删除,然后分配给程序符合大小的内存空间,多余的空间会回收到空闲链表中。如果不停地申请空间确没有使用delete释放,会造成内存不停的增长,这就是所谓的内存泄漏(由于程序员的失误,没有对在堆区申请的内存进行释放)

空间大小的不同

在windows下,栈是一块连续的内存区域,其大小是在编译时就确定的常数

vs2010 可以在项目中右键--属性窗口---链接器---系统---堆栈保留大小,这里可以更改栈的大小,默认是1M的大小

堆是不连续的区域,由链表串联起来。这些串联起来不连续的空间就组成了堆。堆的上限是由系统的有效虚拟内存来决定的。

执行效率的不同

由系统分配,速度快,但是程序员不能对其进行操作

由程序员分配内存,由于机制上的缘故,效率慢,容易产生内存碎片,但是使用方便

执行函数时的不同

 由于栈是先入后出的特点,所以局部变量和代码入栈的顺序和代码表现的顺序正好相反,比如说:函数的参数都是从右到左的入栈顺序。栈有一个特点:数据不断入栈,它的内存地址就会不断减小

 同“系统响应的不同”

 

 总结:栈的内存小,效率高,存储的数据局部有效,超出局部就消失。

             堆可存储空间大,灵活性高,但容易产生碎片,效率低。

 

 三.内存泄漏

假如我们没有使用delete删除一个指针指向的堆区内存空间,然后就将这个指针重新赋值,如

  1. int *p=new int();  
  2. p=new int();  

上面的代码就会造成传说中的内存泄漏。这是因为第一行定义一个指针p指向一块堆区的内存空间。第二行又将新的内存空间地址赋给了p,这样,第一行申请的内存空间由于没有了指向它的指针,也就没办法手动回收了,所以在使用new分配了内存空间后一定要使用delete来释放它。

如果不想删除第一块内存空间,必须这样做,如下:

  1. int *p=new int();  
  2. int *p1=new int();  

 

 

 


 

 

 

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多