C++ 堆 和 堆 分析

【摘要】
	堆和栈,即是数据结构,又是分配存储空间的不同方式。在数据结构上。堆是树型层次结构,结点按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。

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

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

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

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

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

时间: 09-21

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

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

Eclipse Memory Analyzer(MAT)是著名的跨平台集成开发环境 Eclipse Galileo 版本的 33 个组成项目中之一,它是一个功能丰富的 JAVA 堆转储文件分析工具,可以帮助你发现内存漏洞和减少内存消耗.本文主要介绍如何安装配置 Memory Analyzer,并结合一个实例,介绍如何利用 MAT 来进行堆转储文件分析,找到内存泄露的根源. 0 评论: 仇 璐, 软件工程师, IBM 杨 晓峰, 软件工程师, IBM 2010 年 7 月 22 日 内容 在 IB

Eclipse Memory Analyzer 进行堆转储文件分析

概述 对于大型 JAVA 应用程序来说,再精细的测试也难以堵住所有的漏洞,即便我们在测试阶段进行了大量卓有成效的工作,很多问题还是会在生产环境下暴露出来,并且很难在测试环境中进行重现.JVM 能够记录下问题发生时系统的部分运行状态,并将其存储在堆转储 (Heap Dump) 文件中,从而为我们分析和诊断问题提供了重要的依据. 通常内存泄露分析被认为是一件很有难度的工作,一般由团队中的资深人士进行.不过,今天我们要介绍的 MAT(Eclipse Memory Analyzer)被认为是一个“傻瓜式

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

转载地址:http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html Eclipse Memory Analyzer(MAT)是著名的跨平台集成开发环境 Eclipse Galileo 版本的 33 个组成项目中之一,它是一个功能丰富的 JAVA 堆转储文件分析工具,可以帮助你发现内存漏洞和减少内存消耗.本文主要介绍如何安装配置 Memory Analyzer,并结合一个实例,介绍如何利用 MAT 来进行堆转储文

堆及堆的变种

堆及堆的变种 声明 参考课件和讲授来自Accelerator,分析懒得打也来自他 堆的元素删除 借用标记的思想,我们维护一个和原堆同样性质(大根,小根)的堆,每次删除就把它扔到标记堆里面 当我们需要 pop 的时候,如果堆顶元素和删除堆顶元素相同, 那么就说明这个元素是我们之前删除过的,于是我们就在删除堆里面和这个堆里面同时 pop, 然后考察下一元素. 容易发现时间复杂度和空间复杂度没有什么实质性的变化. 题 luogu P3545 [POI2012]HUR-Warehouse Store 我

数据结构之二叉堆(构建堆,堆排序)-(七)

/* * @author Lip * @date 2015-04-23 */ public class Heap { public static void main(String[] args) { // TODO Auto-generated method stub //System.out.println((int)-1.5); int []array={4,2,7,9,3,6,1,12,10,5}; System.out.println("原始:"); printHeapByLe

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

SQL0973N在 "<堆名>" 堆中没有足够的存储器可用来处理语句. 解释: 已使用此堆的所有可用内存.不能处理该语句. 用户响应: 接收到此消息(SQLCODE)后就终止应用程序.修改 "<堆名称>"配置参数以增大堆大小. 例如,要更新数据库配置参数,发出如下命令: db2 update db cfg  for "<db-name>"  using "<heap-name>"

C#中的堆栈与堆(托管堆) [转自互联网]

首先堆栈和堆(托管堆)都在进程的虚拟内存中.(在32位处理器上每个进程的虚拟内存为4GB)堆栈stack : 堆栈中存储值类型.   堆栈实际上是向下填充,即由高内存地址指向地内存地址填充.   堆栈的工作方式是先分配内存的变量后释放(先进后出原则).   堆栈中的变量是从下向上释放,这样就保证了堆栈中先进后出的规则不与变量的生命周期起冲突!   堆栈的性能非常高,但是对于所有的变量来说还不太灵活,而且变量的生命周期必须嵌套. 通常我们希望使用一种方法分配内存来存储数据,并且方法退出后很长一段时

堆是堆,栈归栈

堆是堆,栈归栈 在阅读以下内容之前,请了解一下几点: 第一:坚决澄清:堆是堆,栈归栈. 第二:曾经的“堆栈”再不允许重谈,简直就是扯淡! 第三:下面内容均属于从内存分配角度的阐述,不要与数据结构混淆. [1]程序的内存分配 (1)内存分配详解 一个由C/C++编译的程序占用的内存分为以下几个部分 <1>栈区(stack)— 由编译器自动分配释放,存放函数的参数值,局部变量的值等. <2>堆区(heap) — 一般由程序员设计分配及释放,若程序员不释放,程序结束时可能由OS回收.可能

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

Description 公交车一共经过N(1<=N<=20000)个站点,从站点1一直驶到站点N.K(1<=K<=50000)群奶牛希望搭乘这辆公交车.第i群牛一共有Mi(1<=Mi<=N)只. 他们希望从Si到Ei去.公交车只能座C(1<=C<=100)只奶牛.而且不走重复路线,请计算这辆车最多能满足多少奶牛听要求.注意:对于每一群奶牛,可以部分满足,也可以全部满足,也可以全部不满足. Input 第1行: 三个整数: K,N,C. 由空格隔开. 第2..