首先,我们举一个例子:
void f() { int* p=new int[5]; }
这条短短的一句话就包含了堆与栈,看到new,我们首先就应该想到,我们分配了一块堆内存,那么指针p呢?他分配的是一块栈内存,所以这句话的意思就是:在栈内存中存放了一个指向一块堆内存的指针p。在程序会先确定在堆中分配内存的大小,然后调用operator new分配内存,然后返回这块内存的首地址,放入栈中,他在VC6下的汇编代码如下:
00401028 push 14h
0040102A call operator new (00401060)
0040102F add esp,4
00401032 mov dword ptr [ebp-8],eax
00401035 mov eax,dword ptr [ebp-8]
00401038 mov dword ptr [ebp-4],eax
这里,我们为了简单并没有释放内存,那么该怎么去释放呢?是delete p么?澳,错了,应该是delete []p,这是为了告诉编译器:我删除的是一个数组,VC6就会根据相应的Cookie信息去进行释放内存的工作。
好了,我们回到我们的主题:堆和栈究竟有什么区别?
主要的区别由以下几点:
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可是相当困难的:)
分享到:
相关推荐
"堆和栈的区别和联系" 堆和栈是 C 语言中两个基本的存储区,它们是程序中实现数据存储的方式。了解堆和栈的区别和联系是非常重要的,因为它们对程序的运行和内存管理有着至关重要的影响。 栈 栈是一块自动分配和...
C++中,内存分为5个区:堆、栈、自由存储区、全局/静态存储区和常量存储区。 栈:是由编译器在需要时自动分配,不需要时自动清除的变量存储区。通常存放局部变量、函数参数等。 堆:是由new分配的内存块,由程序员...
综上所述,理解栈和堆的区别与联系,以及它们在更广泛的内存管理框架中的角色,对于成为高效的软件开发者至关重要。每种存储类型都有其适用场景,正确地选择和使用,可以极大地提升程序的性能和稳定性。
### Java中堆内存和栈内存详解 #### 一、引言 在Java编程语言中,内存管理是一项核心技能。为了更好地理解和使用Java,必须清楚地了解堆内存与栈内存的区别及其工作原理。本文将深入探讨Java中堆内存与栈内存的概念...
### 堆内存和栈内存详解 #### 一、预备知识—程序的内存分配 当一个程序被编译并运行时,它所占用的内存会被分成几个不同的区域,每个区域都有其特定的功能和管理方式。以下是对这些内存区域的具体解释: 1. **栈...
### C++中数组与链表的区别与联系 #### 一、基本概念介绍 在C++编程语言中,数组和链表都是用来存储一系列相同类型数据的容器,它们各自有着独特的特性...同时,了解堆和栈的不同特点也有助于更高效地管理内存资源。
在C语言中,数组和指针是两个非常重要的概念,它们之间既有明显的区别,也有紧密的联系。数组是一种数据结构,而指针则是一种特殊的数据类型,用于存储内存地址。理解这两者的差异和关联对于深入学习C语言至关重要。...
### 区别与联系 1. **内存分配**:`new`创建的对象存在于堆内存,其大小在运行时确定,可以很大。而直接定义的对象通常在栈内存,大小在编译时已知,通常较小。 2. **生命周期**:`new`创建的对象由程序员控制释放...
4. 堆和栈的区别 堆和栈是两种不同的内存管理方式。栈是一块连续的内存区域,是由编译器自动管理的,无需手工控制。堆是向高地址扩展的数据结构,是不连续的内存区域,释放工作由程序员控制,容易产生 memory leak...
- 堆和栈都是内存的一部分,用于存储程序运行时的数据。 - 两者都可以通过指针间接访问其存储的数据。 - 都可以存储不同类型的数据,包括基本数据类型、对象等。 #### 四、内存区域的实际应用案例 考虑以下示例...
在编程领域,C 和 C++ 是两种广泛使用的编程语言,尽管它们有着紧密的联系,但也有显著的区别。本文将探讨这些差异,以及它们在实际应用中的作用。 首先,我们来看 C 与 C++ 的主要区别之一:函数参数传递。在 C++ ...
题型7:堆和栈的访问控制 写一个程序,堆可以访问,栈不可以访问。写一个程序,栈可以访问,堆不可以访问。 ``` class heap { private: heap () { cout堆可以访问,栈不可以访问"; } ~heap () { } }; class ...
堆和栈是内存管理的两个重要概念,理解它们的工作原理和分配策略,有助于避免内存泄漏和提高程序效率。 对于非科班出身的程序员,自学Java的过程中可能会遇到计算机基础知识的困扰,但这些知识并非无法克服。通过...
3. 堆和栈的区别: - 栈:由编译器自动分配和释放,主要用于存储局部变量、函数参数和返回地址,内存管理效率高,但空间有限。 - 堆:由程序员分配和释放(如果不释放,程序结束时可能由操作系统回收),主要用于...
* 堆和栈的概念 面向对象 * 面向对象编程基础 * 单例设计模式 * 封装、继承、多态 * 抽象类与接口 * 接口回调、闭包、内部类 * 异常处理 多线程 * 多线程基础 * 线程池 * volatile关键字 * HandlerThread、...
4. 堆和栈的区别。这里要求应聘者能够区分两种内存分配方式的原理、效率、大小限制、碎片化问题以及分配释放机制,这是编程中非常基础但又极其重要的知识点。 5. 键-值编码(KVC)和键路径(KVC)的概念。这是iOS...
- 了解堆和栈内存的区别,以及对象在内存中的分配。 - 熟悉Java的垃圾回收机制,包括引用类型(强、软、弱、虚引用)及其作用。 - 掌握JVM内存模型(堆、方法区、栈、本地方法栈、程序计数器)。 3. **集合框架*...
-Xms -Xmx -Xss的含义三、Java内存中堆和栈的区别——内存分配策略需要先了解区别四、元空间、堆、线程独占部分间的联系——内存角度五、不同JDK版本之间的intern()方法的区别——JDK6 VS JDK6+