几何尺寸与公差论坛

 找回密码
 注册
查看: 3225|回复: 10

【转帖】stack与heap的不同之处

[复制链接]
发表于 2007-5-14 15:09:03 | 显示全部楼层 |阅读模式
1.申请方式           
  stack:           
  
由系统自动分配。     例如,声明在函数中一个局部变量     int     b;     系统自动在栈中为b开辟空间           
  heap:           
  
需要程序员自己申请,并指明大小,在cmalloc函数           
  
p1     =     (char     *)malloc(10);           
  
C++中用new运算符           
  
p2     =     (char     *)malloc(10);           
  
但是注意p1p2本身是在栈中的。           
      
      
  2     
申请后系统的响应           
      
  
栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。           
  
堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,           
  
会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。           
      
  3.
申请大小的限制           
  
栈:在Windows,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。           
  
堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。           
      
      
  4.
申请效率的比较:           
  
栈由系统自动分配,速度较快。但程序员是无法控制的。           
  
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.           
  
另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。           
      
  5.
堆和栈中的存储内容           
  
栈:     在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。           
  
当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。           
  
堆:一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。           
      
  6.
存取效率的比较           
      
  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;           
  }           
  
堆和栈的区别可以用如下的比喻来看出:           
  
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。           
  
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。  
 楼主| 发表于 2007-5-14 15:09:23 | 显示全部楼层

回复: 【转帖】stack与heap的不同之处

stack是把推进栈里的元素按照先进后出的顺序逐一的弹出,heap是允许用户以任何次序将任何元素推入容器内,但取出时一定是从优先级最高的元素开始取.max-heapmin-heap两种.max-heap首先取出的是推入容器中的最大的元素,min-heap首先取出的是推入容器中的最小的元素.
 楼主| 发表于 2007-5-14 15:09:44 | 显示全部楼层

回复: 【转帖】stack与heap的不同之处

使用动态内存分配而得到的空间是在heap中分配的,而自动变量(局部非静态变量)则是在stack上分配的,如果你需要返回一个可用的指针,则使用new或者malloc等函数分配内存。动态分配的内存必须明确地释放,否则会造成内存泄漏。
 楼主| 发表于 2007-5-14 15:10:17 | 显示全部楼层

回复: 【转帖】stack与heap的不同之处

局部变量存放在stack中,块结束时释放;   
  
动态申请的内存放在heap中,要由手工释放
 楼主| 发表于 2007-5-14 15:10:50 | 显示全部楼层

回复: 【转帖】stack与heap的不同之处

stack   从高地址往低地址分配;  heap   相反;   
   
  
你在程序里newalloc一个对象就是从heap分配的,   
  
而你调用函数时的参数是利用stack来存储的(压入栈),   
   
  
简单的说,堆用来分配对象空间,栈用来保存函数调用现场
 楼主| 发表于 2007-5-14 15:11:12 | 显示全部楼层

回复: 【转帖】stack与heap的不同之处

再说白了,没有堆你就不能给程序分配内存;没有栈你就不能调用函数
 楼主| 发表于 2007-5-14 15:11:23 | 显示全部楼层

回复: 【转帖】stack与heap的不同之处

先看以下汇编,就知道stack了,   
  
再看以下C++new/delete就知道heap了。  

栈在汇编代码中表示成PUSH   POP,用的是ESS段,SP寄存器;

  而堆不是,是在内存中读写,EDS
 楼主| 发表于 2007-5-14 15:11:38 | 显示全部楼层

回复: 【转帖】stack与heap的不同之处

C++包括两种被应用程序管理的内存区域:一种称为栈(stack),另一种称为堆(heap)   
  stack
是函数被调用时自动分配的一块内存区域,它主要用于保留函数内使用的变量及函数调用位置处下一条代码的地址。   
  stack
是后进先出,一个可变的指针指向stack的顶部。   
  
本质上,当一个函数被程序调用时,当前的执行地址被放入stack,如果有参数传递到函数内,这些参数也被压入stack,如果函数内有变量,它们也被压入stack,如果函数执行时调用另一个函数,重复上面的过程。   
  
当从函数返回时,stack指针指向存放先前执行地址的位置,也就是说,stack空间内分配的元素已被删除。这就是为什么函数内的变量此时无效,因为它们已经被推出了stack,另外要注意的是,声明一个静态变量,它没有进入stack中。   
  
另一种由应用程序管理的内存区域是堆(heap),heap是储存应用程序的内存分配需求,并且分离于程序代码和stack,heap中分配的对象的总的空间受限于计算机系统中有效的虚拟内存。   
  C
程序通常使用mallocfree分配和回收heap内存,在C++中,使用newdelete.  
 楼主| 发表于 2007-5-14 15:12:04 | 显示全部楼层

回复: 【转帖】stack与heap的不同之处

如果一个变量在stack上被创建,当程序运行到包含这个变量定义的最小的{}对的左“}”0时,变量就会被清除。而在heap上创建的变量,只有显式调用delete或者当程序运行结束时才被清除。   
        
另外,一个线程不能访问另一个线程的stack。而heap是进程中所有线程共享的。
 楼主| 发表于 2007-5-14 15:12:34 | 显示全部楼层

回复: 【转帖】stack与heap的不同之处

什么是堆?     
  
(如果您已经知道什么是堆,可以跳到什么是常见的堆性能问题?部分)     
  
在程序中,使用堆来动态分配和释放对象。在下列情况下,调用堆操作:     
   
  
事先不知道程序所需对象的数量和大小。     
  
对象太大而不适合堆栈分配程序。     
   
  
堆使用了在运行时分配给代码和堆栈的内存之外的部分内存。下图给出了堆分配程序的不同层。     
  http://www.microsoft.com/china/msdn/library/images/heap3.gif     
  GlobalAlloc/GlobalFree
Microsoft   Win32   堆调用,这些调用直接与每个进程的默认堆进行对话。     
  LocalAlloc/LocalFree
Win32   堆调用(为了与   Microsoft   Windows   NT   兼容),这些调用直接与每个进程的默认堆进行对话。     
  COM   
   IMalloc   分配程序(或   CoTaskMemAlloc   /   CoTaskMemFree):函数使用每个进程的默认堆。自动化程序使用组件对象模型   (COM)”的分配程序,而申请的程序使用每个进程堆。     
   
  C/C++   
运行时   (CRT)   分配程序:提供了   malloc()      free()   以及   new        
  delete   
操作符。如   Microsoft   Visual   Basic      Java   等语言也提供了新的操作符并使用垃圾收集来代替堆。CRT   创建自己的私有堆,驻留在   Win32   堆的顶部。     
   
  Windows   NT   
中,Win32   堆是   Windows   NT   运行时分配程序周围的薄层。所有     
  API   
转发它们的请求给   NTDLL     
  Windows   NT   
运行时分配程序提供   Windows   NT   内的核心堆分配程序。它由具有128   个大小从   8      1,024   字节的空闲列表的前端分配程序组成。后端分配程序使用虚拟内存来保留和提交页。     
  
在图表的底部是虚拟内存分配程序,操作系统使用它来保留和提交页。所有分配程序使用虚拟内存进行数据的存取。     
  
分配和释放块不就那么简单吗?为何花费这么长时间?     
  
堆实现的注意事项     
  
传统上,操作系统和运行时库是与堆的实现共存的。在一个进程的开始,操作系统创建一个默认堆,叫做进程堆。如果没有其他堆可使用,则块的分配使用进程堆。语言运行时也能在进程内创建单独的堆。(例如,C   运行时创建它自己的堆。)除这些专用的堆外,应用程序或许多已载入的动态链接库   (DLL)   之一可以创建和使用单独的堆。Win32   提供一整套   API   来创建和使用私有堆。有关堆函数(英文)的详尽指导,请参见   MSDN     
  
当应用程序或   DLL   创建私有堆时,这些堆存在于进程空间,并且在进程内是可访问的。从给定堆分配的数据将在同一个堆上释放。(不能从一个堆分配而在另一个堆释放。)     
  
在所有虚拟内存系统中,堆驻留在操作系统的虚拟内存管理器的顶部。语言运行时堆也驻留在虚拟内存顶部。某些情况下,这些堆是操作系统堆中的层,而语言运行时堆则通过大块的分配来执行自己的内存管理。不使用操作系统堆,而使用虚拟内存函数更利于堆的分配和块的使用。     
  
典型的堆实现由前、后端分配程序组成。前端分配程序维持固定大小块的空闲列表。对于一次分配调用,堆尝试从前端列表找到一个自由块。如果失败,堆被迫从后端(保留和提交虚拟内存)分配一个大块来满足请求。通用的实现有每块分配的开销,这将耗费执行周期,也减少了可使用的存储空间。  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

QQ|Archiver|小黑屋|几何尺寸与公差论坛

GMT+8, 2024-12-22 18:45 , Processed in 0.047787 second(s), 19 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表