1.堆和栈的区别
1、管理方式不同;
2、空间大小不同;
3、能否产生碎片不同;
4、生长方向不同;
5、分配方式不同;
6、分配效率不同;
管理方式:对于栈来讲,是由编译器自动管理,无需我们手工控制;对于堆来说,释放工作由程序员控制,容易产生memory leak。
空间大小:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。但是对于栈来讲,一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M(好像是,记不清楚了)。当然,我们可以修改:
打开工程,依次操作菜单如下:Project->Setting->Link,在Category 中选中Output,然后在Reserve中设定堆栈的最大值和commit。
注意:reserve最小值为4Byte;commit是保留在虚拟内存的页文件里面,它设置的较大会使栈开辟较大的值,可能增加内存的开销和启动时间。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构,这里我们就不再一一讨论了。
生长方向:对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
分配方式:堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由alloca函数进行分配,但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是C/C++函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
从这里我们可以看到,堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以栈在程序中是应用最广泛的,就算是函数的调用也利用栈去完成,函数调用过程中的参数,返回地址,EBP和局部变量都采用栈的方式存放。所以,我们推荐大家尽量用栈,而不是用堆。
虽然栈有如此众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,还是用堆好一些。
无论是堆还是栈,都要防止越界现象的发生(除非你是故意使其越界),因为越界的结果要么是程序崩溃,要么是摧毁程序的堆、栈结构,产生以想不到的结果,就算是在你的程序运行过程中,没有发生上面的问题,你还是要小心,说不定什么时候就崩掉,那时候debug可是相当困难的:)
堆就是,取和放数据没有顺序,想拿哪个拿哪个 栈则不同,先进后出, 从实现角度讲,栈往往用来用于函数的参数和返回值的 传递,在函数退出后,会被pop空,速度很快,就不是于用 长时间的变量; 所以在函数内部的变量,在函数退出后,就被释放掉了; 而如果new的则不同,会放在堆里,函数对出后也不会释放。
2.堆和栈详细解释:
堆栈:线程使用的临时数据存放区。早期的操作系统堆栈依赖于进程而不是线程。windows中堆栈依赖于线程,每一个线程都有独立的堆栈,但是独立的含义不意味着堆栈的地址空间不是在进程中的,他仍然在线程依赖的进程地址空间中分配。windows的纤程使用线程的堆栈。线程切换的时候切换堆栈寄存器,这是自动进行的,不需要应用程序员考虑如何切换,系统程序员需要考虑如何切换,通常,是改变堆栈寄存器使用的门描述符表。
分配堆栈空间:堆栈在线程初始化的时候分配空间,通常继承创建此线程的进程的缺省堆栈规格。这不需要应用程序员干预,通常是设置进程初始化的参数,来改变堆栈的缺省尺寸,在程序运行中不能改变堆栈尺寸。
windows堆和堆栈的区别:堆是和进程相关联的,它是windows为进程预留的地址空间,特别提示:预留的地址空间并不意味着你已经获得了这些空间,在没有真正分配之前你是不能使用的,windows使用两步提交来分配内存。使用堆函数来管理堆。堆又称为全局堆,在windows95的时候,所有进程的堆是在一起的,但是,windows98以后,堆不再是交叉的,而是进程隔离的,全局堆沿用了老的说法。
堆栈的使用:如何使用堆栈通常是编译器的工作,大多数的编译器将函数的内部变量存放在堆栈中,函数的参数通常也是通过堆栈来传递,堆栈传递参数,通常是复制传送,传地址参数并不进行堆栈复制传送。调用函数的时候,编译器一般生成移动堆栈栈顶寄存器的代码,上述过程,高级语言程序员是不可见的,汇编语言程序员通常需要关心。
关于Delphi的堆栈使用:Delphi将全局变量、全局常数和对象类型变量存放在堆当中,将局部变量、常数、简单结构变量存放在堆栈。对象类型的变量的含义是指:类的实例、具有类性质的默认类型(比如string类型)。但是对象的引用变量,如果是局部变量,仍然存放在堆栈,这样的变量相当于指针。结构变量,在堆栈中分配。在Delphi中没有任何函数可以在堆栈中分配空间。
关于C++的堆栈使用:C++中除非你指出了局部变量在堆上面分配,那么所有的局部变量都是在堆栈分配空间的。
堆栈溢出:堆栈的空间分配完了,直观的就是栈顶寄存器的值超过了堆栈寄存器和栈长度-1之和。造成这种情况,通常是递归函数没有返回。一般的,我们的程序不可能由于函数调用深度过大造成堆栈溢出。在C当中这种情况出现的可能要高于Delphi,因为C++会在堆栈上面分配大尺寸的对象。还有一种情况,程序莫名其妙的改变了栈顶寄存器的值,这种情况是可能的,函数返回的时候需要根据保存在堆栈中的原先栈顶寄存器的值来恢复上一级函数的堆栈引用,但是在这个函数中很可能因为错误而修改了这个值。那么再返回的时候就会溢出。
堆栈溢出和缓冲区溢出的差异:缓冲区溢出是指为变量分配的空间小于实际使用的空间。最常见的就是字符串溢出。我们在函数中为字符串变量分配了一段固定长度的空间,但是,函数调用者可能传递了一个超过我们预留长度的字符串,如果我们没有检查传递过来的字符串长度就拷贝到我们的局部变量当中,那么就会破坏紧跟我们字符串变量其他局部变量的内容,缓冲溢出攻击的常见手段就是破坏内容一直到函数的结尾,函数在ret的时候需要使用堆栈中保留的返回地址,这个地址如果被修改成了攻击者希望返回的地址,那么攻击者就可以执行他想执行的任何代码,不过这个手段不是很容易实现的。还有一种比较容易的手段,就是造成异常,从而控制程序,异常的机制我不是很清楚,所以不好讨论。Delphi中字符串都分配在堆当中,所以即使发生溢出,也是和代码段隔离的很好,不会发生问题,C++的程序通常很难避免
发表评论
-
析构函数为虚函数的原因
2012-09-09 11:42 786我们知道,用C++开发的时候,用来做基类的类的析构函数 ... -
hash的应用
2012-08-31 23:02 925第一部分为一道百度面试题Top K算法的详解;第二部分为关 ... -
微软智力题
2012-08-29 19:59 539第一组1.烧一根不均匀的绳,从头烧到尾总共需要1个小时。现在有 ... -
C++不能被继承的类
2012-08-27 20:16 998一个类不能被继承, ... -
括号对齐问题
2012-08-27 10:47 1353解法一:左右括号成一对则抵消 可以 ... -
树的遍历
2012-08-19 10:43 680/****************************** ... -
堆排序
2012-08-16 14:24 844堆:(二叉)堆数据结构是一种数组对象。它可以被视为一棵完全 ... -
多态赋值
2012-08-14 16:16 778#include <iostream> usi ... -
static变量与static函数(转)
2012-08-13 10:15 703一、 static 变量 static变量大致分为三种用法 ... -
不用sizeof判断16位32位
2012-08-10 15:21 1664用C++写个程序,如何判断一个操作系统是16位还是3 ... -
找出连续最长的数字串(百度面试)
2012-08-09 15:15 1112int maxContinuNum(const char*in ... -
顺序栈和链栈
2012-08-06 10:01 767顺序栈:话不多说直接上代码 #include ... -
队列的数组实现和链表实现
2012-08-05 16:20 995话不多少,数组实现上代码: #include<i ... -
KMP算法详解
2012-08-02 21:40 850KMP算法: 是在一个“主文本字符串” ... -
字符串的最长连续重复子串
2012-08-01 15:05 9701两种方法: 循环两次寻找最长的子串: <方法一> ... -
寻找一个字符串连续出现最多的子串的方法(转)
2012-07-31 21:19 919算法描述首先获得后缀数组,然后1.第一行第一个字符a,与第二行 ... -
字符串的循环移位
2012-07-31 16:52 937假设字符串:abcdefg 左循环两位:cdefgab 右 ... -
一次谷歌面试趣事(转)
2012-07-31 15:26 729很多年前我进入硅谷 ... -
约瑟夫环问题(循环链表)
2012-07-30 21:31 1242题目描述:n只猴子要选大王,选举方法如下:所有猴子按 1, ... -
面试之单链表
2012-07-30 20:18 6921、编程实现一个单链表的建立/测长/打印。 ...
相关推荐
本文分析了Java中堆内存与栈内存分配的异同
内存中堆和栈的分配区别,程序的内存分配,堆和栈的理论知识
很详细清楚的介绍堆和栈的包含内容,内存区别,以及怎么分配。
C语言程序编译的内存分配,堆与栈的区别 C语言程序编译的内存分配,堆与栈的区别 C语言程序编译的内存分配,堆与栈的区别
C和C++动态内存分配如堆,栈,数据段
Java把内存划分成两种:一种是栈内存,一种是堆内存。 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过...
C,C++内存分配的详细讲解包括堆,栈,数据段的分配管理
详细的讲解了java内存分配,包括运行时堆和栈内存的分配,变量和方法存储等
内存分配——静态存储区 栈 堆.doc 很好的讲解。
Java中堆与栈的内存分配
一、预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈 2、堆区(heap) ...
堆和栈内存分配实用.pdf
在进程私有的内存里分配,又有两种分配情况,一种上基于栈式的内存分配,另一种是基于堆内存的分配。在c++里使用堆内存分配是使用HeapAlloc函数来实现的,也就是实现new操作符分配内存时会调这个函数。
Java内存分配之堆、栈和常量池 Java内存分配主要包括以下几个区域:1. 寄存器:我们在程序中无法控制2. 栈:存放基本类型的数据和对象的引用,但对象本身不
讲述C语言的内存分配中,堆与栈的概念,以及如何在编程中规划堆与栈的设计
内存区划分、内存分配、常量存储区、堆、栈、自由存储区、全局区[C++][内存管理].PDF
关于内存分配的文档,分别讨论堆和栈的特点
Java中分配堆内存是自动初始化的,即为一个对象分配内存的时候,会初始化这个对象中变量。虽然Java中所有对象的存储空间都是在堆中分配的,但是这个对象的引用却是在栈中分配,也就是说在建立一个对象时在堆和栈中都...