`
蒙面考拉
  • 浏览: 162514 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

内存分配---堆与栈

 
阅读更多

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++的程序通常很难避免

分享到:
评论

相关推荐

    Java中堆内存与栈内存分配浅析

    ### Java中堆内存与栈内存分配浅析 #### 一、引言 在Java编程语言中,内存管理是一项至关重要的技术。程序运行时所使用的内存主要分为两类:堆内存(Heap Memory)和栈内存(Stack Memory)。理解这两种内存类型的...

    内存中堆和栈的分配区别

    在计算机科学领域,内存管理是实现程序高效运行的关键技术之一,而其中的堆(Heap)与栈(Stack)是两种核心的内存分配方式。本文将深入探讨这两种内存区域的分配区别,以及它们在程序中的作用机制,帮助读者理解C/...

    【LINUX】关于动态内存分配的理解

    - 动态内存分配和静态内存分配之间存在区别,静态内存分配在栈上进行,由编译器分配和系统自动释放;动态内存分配在堆上进行,由程序员自行管理内存的申请和释放。 在实际的软件开发中,正确使用动态内存分配能够...

    堆和栈内存分配(详细)

    ### 堆和栈内存分配详解 在计算机科学中,理解和掌握堆和栈的内存管理机制对于编程至关重要,尤其是在资源管理和性能优化方面。本文将深入探讨堆和栈的区别,包括它们的内存分配特点、应用场景以及如何高效利用这两...

    第9章 L3动态内存分配-基本概念1

    动态内存分配器负责管理进程的虚拟内存区域,这部分区域被称为堆。堆是程序中一个连续的内存区域,包含了代码段、已初始化数据段、未初始化数据段以及用户栈。 动态内存分配器将堆视为由多个不同大小的块(blocks)...

    堆内存和栈内存详解.doc

    - 堆的内存分配更灵活,但也更容易产生内存碎片。 ##### 2.4 申请效率的比较 - **栈** - 由系统自动管理,分配速度快。 - **堆** - 通过 `malloc()` 或 `new` 分配内存,速度较慢。 - 容易产生内存碎片。 - ...

    Java中堆内存和栈内存详解

    Java的内存分配策略主要包括静态分配、栈式分配和堆式分配。其中,栈式分配和堆式分配是运行时动态进行的,具体如下: 1. **栈式存储分配**:栈式存储适用于已知大小的局部变量和方法参数。当一个方法被调用时,JVM...

    内存分配——静态存储区 栈 堆.doc

    ### 内存分配详解:静态存储区、栈与堆 #### 一、内存基本构成 在计算机编程中,内存管理是十分重要的一个方面。合理的内存分配不仅能够提高程序的运行效率,还能有效避免一些常见的编程错误,比如内存泄漏。本文...

    堆和栈的内存分配浅谈

    《堆和栈的内存分配解析》 在计算机编程中,堆和栈是两种重要的内存管理方式,它们在程序运行过程中起着至关重要的作用。理解它们的特性与差异,有助于我们编写更高效、更稳定的程序。 首先,让我们了解一下堆和栈...

    C语言入门-堆与栈的区别

    与栈不同的是,堆上的内存分配与释放需要程序员手动控制。 **特点:** 1. **动态分配:** 堆上的内存可以通过`malloc()`、`calloc()`、`realloc()`等函数动态分配,并且需要通过`free()`函数显式释放。 2. **大小...

    c++堆和栈及内存的使用分配

    栈区的特点是存取速度快,但空间有限,通常只有几MB大小,且栈内存分配和释放必须遵循先进后出(LIFO)的原则。 **二、堆区(Heap)** 堆区则由程序员负责分配和释放。如果不手动释放,程序结束时可能会由操作系统...

    堆与栈的区别

    - 栈内存分配快速,因为它是预设大小的连续内存区域,通常在Windows环境下大小为2MB左右,如果分配的内存超过了栈的剩余空间,会导致栈溢出。 2. **堆(Heap)**: - 堆是一种动态内存分配的方式,程序员负责申请...

    探究内存中栈、堆和数据区的分配和管理

    - **运行时**:则是程序运行过程中动态发生的内存分配行为,主要通过栈和堆进行。 #### 存储时内存分配详解 ##### 代码区(Text Section) - **定义**:存放程序运行时所需的机器指令。 - **特性**: - **共享性...

    C,C++内存分配的详细讲解包括堆,栈,数据段等.pdf

    - 栈内存分配速度快,但空间有限;堆内存分配慢,但空间大且可定制。 - 栈内存的内存块在栈顶分配,遵循LIFO(后进先出)原则;堆内存则可以在任何位置分配。 - 栈内存中存在溢出风险,堆内存中存在内存泄漏问题。 -...

    C语言程序编译的内存分配,堆与栈的区别

    ### C语言程序编译的内存分配,堆与栈的区别 在C语言编程中,了解程序在运行时如何分配内存对于优化代码性能、避免内存泄漏等问题至关重要。本文将深入探讨C语言程序编译过程中内存的分配机制,特别是堆(heap)与...

    堆和栈的区别,详细描述了堆栈的分配和使用原理

    栈内存分配快速,但空间有限,通常由系统设定一个固定的大小,如Windows下的2MB或1MB。 堆(Heap)则是程序员手动进行分配和释放的内存区域。通过C/C++中的`malloc`或C++的`new`运算符来申请内存,程序员需要负责...

    内存分配模拟程序-OS

    - **地址空间**:每个进程都有一个独立的虚拟地址空间,包含代码、数据、堆、栈等区域。 2. **内存分配策略:** - **连续分配**:早期操作系统采用的方法,将内存连续划分给进程,包括单一连续分配(所有进程共享...

    堆和栈内存分配实用.pdf

    接下来,堆(Heap)是一种可动态分配的内存区域,与栈的自动分配和回收不同,堆上的内存分配是显式进行的,需要程序员通过代码来控制。在C语言中,堆内存分配常常通过函数malloc或calloc实现,而在C++中,可以使用...

    堆内存和栈内存详解 ESP

    #### 一、预备知识—程序的内存分配 当一个程序被编译并运行时,它所占用的内存会被分成几个不同的区域,每个区域都有其特定的功能和管理方式。以下是对这些内存区域的具体解释: 1. **栈区(stack)**: - **...

Global site tag (gtag.js) - Google Analytics