【摘要】
	堆和栈,即是数据结构,又是分配存储空间的不同方式。在数据结构上。堆是树型层次结构,结点按keyword次序排列,经常使用的堆为二叉堆;栈是一种先进后出的数据结构。在内存分配上的堆和栈,首要差别在于申请方式不同。其次在存取速度、存储空间的大小、存储内容(一定要记住,栈中是第一条可运行语句地址。然后是各个參数。堆中头部是堆的大小描写叙述。之后有程序猿自己安排)、内存中的相对位置和系统相应的响应上都各有自己差别。在C语言 的学习过程中,堆和栈即是基础也是重点。

【正文】
	堆栈是一个非常模糊的概念,堆栈:一种数据结构?一个在程序执行时用于存放的地方?这可能是非常多刚開始学习的人的认识,由于,我以前就是这么想的和汇编语言中的堆栈一词混为一谈。
数据结构中的堆栈
实际上堆栈是两种数据结构:堆和栈。堆和栈都是一种数据项按序排列的数据结构。
栈是一种具有后进先出性质的数据结构,也就是说后存放的先取,先存放的后取。

这就如同我们要取出放在箱子里面底下的东西(放入的比較早的物体)。我们首先要移开压在它上面的物体(放入的比較晚的物体)。而堆就不同了,堆是一种经过排序的树形数据结构。每一个结点都有一个值。通常我们所说的堆的数据结构。是指二叉堆。

堆的特点是根结点的值最小(或最大),且根结点的两个子树也是一个堆。因为堆的这个特性。经常使用来实现优先队列,堆的存取是随意。

这就如同我们在图书馆的书架上取书。尽管书的摆放是有顺序的,可是我们想取随意一本时不必像栈一样,先取出前面全部的书,书架这样的机制不同于箱子。我们能够直接取出我们想要的书。

	可是,重点并不在数据结构的堆和栈,之所以要说数据结构的堆和栈是为了和堆区和栈区差别开来。

内存分配中的堆栈
以下就说说C语言程序内存分配中的堆和栈,这里有必要把内存分配也提一下。大家不要嫌我啰嗦。普通情况下程序存放在Rom(仅仅读内存,比方硬盘)或Flash中,执行时须要拷到RAM(随机存储器RAM)中执行。RAM会分别存储不同的信息,例如以下图所看到的:


内存中的栈区处于相对较高的地址。栈地址是向下增长的,栈中分配局部变量空间,堆区处于相对较低的地址。是向上增长的用于分配程序猿申请的内存空间。

另外还有静态区是分配静态变量,全局变量空间的仅仅读区是分配常量和程序代码空间的。以及其它一些分区。

来看一个网上非常流行的经典样例:
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); //堆
}

内存分配中堆和栈的差别与联系

1. 申请方式不同(首要差别)
栈(英文名称是stack)是系统自己主动分配空间的。比如我们定义一个 char a;系统会自己主动在栈上为其开辟空间。
堆(英文名称是heap)是程序猿依据须要自己申请的空间。比如malloc(10);开辟十个字节的空间。
因为栈上的空间是自己主动分配自己主动回收的,所以栈上的数据的生存周期仅仅是在函数的执行过程中,执行后就释放掉,不能够再訪问。而堆上的数据仅仅要程序猿不释放空间,就一直能够訪问到,只是缺点是一旦忘记释放会造成内存泄露。

2. 申请后系统的响应 
栈:仅仅要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
堆:首先应该知道操作系统有一个记录空暇内存地址的链表,当系统收到程序的申请时。会遍历该链表。寻找第一个空间大于所申请空间的堆结点,然后将该结点从空暇结点链表中删除,并将该结点的空间分配给程序。另外,对于大多数系统。会在这块内存空间中的首地址处记录本次分配的大小。这样,代码中的 delete语句才干正确的释放本内存空间。另外,因为找到的堆结点的大小不一定正好等于申请的大小。系统会自己主动的将多余的那部分又一次放入空暇链表中。也就是说堆会在申请后还要做一些兴许的工作这就会引出申请效率的问题 

3. 申请效率的比較
栈由系统自己主动分配,速度较快。但程序猿是无法控制的。 
堆是由new分配的内存。一般速度比較慢,并且easy产生内存碎片,只是用起来最方便。
   
4. 堆和栈中的存储内容 
栈: 在函数调用时,第一个进栈的是主函数中函数调用后的下一条指令(函数调用语句的下一条可执行语句)的地址。然后是函数的各个參数。

在大多数的C编译器中,參数是由右往左入栈的。然后是函数中的局部变量。注意静态变量是不入栈的。 当本次函数调用结束后。局部变量先出栈,然后是參数,最后栈顶指针指向最開始存的地址,也就是主函数中的下一条指令。程序由该点继续执行。
堆:通常是在堆的头部用一个字节存放堆的大小。堆中的详细内容有程序猿安排。 

5. 存取效率的比較 
char s1[] = "aaaaaaaaaaaaaaa"; 
char *s2 = "bbbbbbbbbbbbbbbbb"; 
aaaaaaaaaaa是在执行时刻赋值的。 
而bbbbbbbbbbb是在编译时就确定的; 
可是,在以后的存取中。在栈上的数组比指针所指向的字符串(比如堆)快。
  【例】 
  #include 
  void main() 
  { 
  char a = 1; 
  char c[] = "1234567890"; 
  char *p ="1234567890"; 
  a = c[1]; 
  a = p[1]; 
  return; 
  } 
  【相应的汇编代码 】
  10: a = c[1]; 
  00401067 8A 4D F1 mov cl,byte ptr [ebp-0Fh] 
  0040106A 88 4D FC mov byte ptr [ebp-4],cl 
  11: a = p[1]; 
  0040106D 8B 55 EC mov edx,dword ptr [ebp-14h] 
  00401070 8A 42 01 mov al,byte ptr [edx+1] 
  00401073 88 45 FC mov byte ptr [ebp-4],al

6. 申请大小的限制 
栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在 WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),假设申请的空间超过栈的剩余空间时。将提示overflow。

因此,能从栈获得的空间较小。 
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。

这是因为系统是用链表来存储的空暇内存地址的。自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见。堆获得的空间比較灵活。也比較大。 

	最后引用一位前辈的比喻来结束堆和栈的差别,使用栈就象我们去饭馆里吃饭,仅仅管点菜(发出申请)、付钱、和吃(使用)。吃饱了就走。不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的优点是快捷,可是自由度小。

使用堆就象是自己动手做喜欢吃的菜肴。比較麻烦,可是比較符合自己的口味。并且自由度大。比喻非常形象,说的非常通俗易懂。我不知道,如果你是一个小的收获。

版权声明:本文博主原创文章,博客,未经同意不得转载。

C++ 堆 和 堆 分析的更多相关文章

  1. 使用 Eclipse Memory Analyzer 进行堆转储文件分析

    Eclipse Memory Analyzer(MAT)是著名的跨平台集成开发环境 Eclipse Galileo 版本的 33 个组成项目中之一,它是一个功能丰富的 JAVA 堆转储文件分析工具,可 ...

  2. 《深入理解Java虚拟机》(六)堆内存使用分析,垃圾收集器 GC 日志解读

    堆内存使用分析,GC 日志解读 重要的东东 在Java中,对象实例都是在堆上创建.一些类信息,常量,静态变量等存储在方法区.堆和方法区都是线程共享的. GC机制是由JVM提供,用来清理需要清除的对象, ...

  3. mat 使用 分析 oom 使用 Eclipse Memory Analyzer 进行堆转储文件分析

    概述 对于大型 JAVA 应用程序来说,再精细的测试也难以堵住所有的漏洞,即便我们在测试阶段进行了大量卓有成效的工作,很多问题还是会在生产环境下暴露出来,并且很难在测试环境中进行重现.JVM 能够记录 ...

  4. [Android Memory] 使用 Eclipse Memory Analyzer 进行堆转储文件分析

    转载地址:http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html Eclipse Memory Analyzer ...

  5. <JVM下篇:性能监控与调优篇>补充:浅堆深堆与内存泄露

    笔记来源:尚硅谷JVM全套教程,百万播放,全网巅峰(宋红康详解java虚拟机) 同步更新:https://gitee.com/vectorx/NOTE_JVM https://codechina.cs ...

  6. 【ZZ】堆和堆的应用:堆排序和优先队列

    堆和堆的应用:堆排序和优先队列 https://mp.weixin.qq.com/s/dM8IHEN95IvzQaUKH5zVXw 堆和堆的应用:堆排序和优先队列 2018-02-27 算法与数据结构 ...

  7. SQL0973N在 "<堆名>" 堆中没有足够的存储器可用来处理语句

    SQL0973N在 "<堆名>" 堆中没有足够的存储器可用来处理语句. 解释: 已使用此堆的所有可用内存.不能处理该语句. 用户响应: 接收到此消息(SQLCODE)后 ...

  8. bzoj 1577: [Usaco2009 Feb]庙会捷运Fair Shuttle——小根堆+大根堆+贪心

    Description 公交车一共经过N(1<=N<=20000)个站点,从站点1一直驶到站点N.K(1<=K<=50000)群奶牛希望搭乘这辆公交车.第i群牛一共有Mi(1& ...

  9. 0day堆(1)堆的管理策略

    基本概念 堆块:堆区内存的基本单位 包括两个部分:块首,块身 块首:标识这个堆块自身的信息:如大小,是否被占用等 块身:分配给用户使用的数据区 堆表:一般位于堆区的起始位置,用于索引堆区所有堆块的信息 ...

随机推荐

  1. EF 执行视图

    IEnumerable<V_stocks> summary = db.Database.SqlQuery<V_stocks>("SELECT * FROM dbo.V ...

  2. apache2.4.4启用deflate压缩

    今天在看<高性能php应用开发>这本书,说道如何启用mod_deflate: 启用如下模块: LoadModule deflate_module modules/mod_deflate.s ...

  3. 关于cocos2dx3.0 UITextField不能使用退格键删除字符的解决方式

    近日開始将项目移植到cocos2dx 3.0版本号,出现了一些问题,UI方面眼下就发现UITextField控件不能响应退格键或者删除键,在Windows以下调试如此,我開始以为是平台支持不好,后来公 ...

  4. Xamarin:制作并发布apk

    原文:Xamarin:制作并发布apk 终于到了激动人心的时刻:要向真机发布apk了.流程如下: 1 制作release版的android应用安装包apk文件: 1.1 用VS2012中文版制作:记得 ...

  5. 使用AngularJS开发下一代Web应用

    原版的:https://github.com/edagarli/AngularJSWeb 来源书:https://github.com/shyamseshadri/angularjs-book 版权声 ...

  6. 构造Nexus,仓库部署成员Nexus仓

    在一个,我们描述了如何配置安装nexus制,本节,我们来介绍nexus采用 1.登录 在红色的部分点击登陆.输入username与password admin/admin123. 这里能够配置nexu ...

  7. 转载:ecshop自定义销量

    转自:http://www.phpally.com/ecshop%E8%87%AA%E5%AE%9A%E4%B9%89%E9%94%80%E9%87%8F/ 本补丁以假乱真,对网站销售有一定帮助,计算 ...

  8. cocos2d-x笔记(十一)Lua发展飞机战争-5- 让飞机动

    然后在飞机上已被添加到游戏,下一步是让它动起来.主要是为了应对触摸事件. 在C++通过重写ccTouchBegan().ccTouchMoved().ccTouchEnded()三个函数来响应触摸事件 ...

  9. [网络]_[0基础]_[使用putty备份远程数据]

    场景: 1. putty是windows上訪问linux服务的免费client之中的一个.用它来ssh到远程server备份数据是常见的做法(在没做好自己主动备份机制前), 通过putty界面尽管也不 ...

  10. Oracle Hints详细解释

    特别介绍给大家Oracle Hints之前,让我们知道下Oracle Hints什么,然后好Oracle Hints,我们希望实际.基于成本的优化器是很聪明,在大多数情况下,将选择正确的优化,减少DB ...