堆和栈的区别

内存中的‘堆’和‘栈’

我们主要讲内存上的堆区和栈区,数据结构中的堆和栈不作分析

理解:
  • 栈区:栈上分配的内存空间是连续的,主要用来存放函数内部的局部变量以及函数参数等,栈由操作系统自动分配,自动释放,生命周期很短,函数调用完,栈就会立马被释放,且栈中不宜存放大量数据,可能会出现栈溢出的问题。
  • 堆区:一般由程序员手动分配空间手动释放,在C语言中用malloc,realloc,calloc函数来开辟动态内存空间,在Java中用new关键字来开辟,C语言中用free()手动释放空间后,要记得对指向该内存空间的指针置空,不然会出现野指针(上一篇博客有详解)的问题,若程序员不释放,事后可能会由操作系统回收(最好还是自己手动释放,以免引起不必要的问题),Java中有垃圾回收机制。
  • 全局区(.data和.bss):存放全局变量以及static修饰的静态变量,分为已初始化数据和未初始化数据,程序结束时就会被释放,全局变量和局部静态变量数据经常放在数据端(.data),未初始化的全局变量和静态变量一般放在叫(.bss)段里
  • 只读常量区:常量字符串就是放在这里的,程序结束时被释放
  • 代码区(.text):存放程序源代码编译后的机器指令
图解:

这里写图片描述

区别:

空间大小的不同:

  • 堆:一般来讲在32位系统下,堆内存可以达到4G的空间,从这个角度来看堆内存几乎是没有什么限制的。
  • 栈:一般都是有一定的空间大小的,例如,在VC6下面,默认的栈空间大小是1M。当然,这个值可以修改。

系统响应的区别:

  • 栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。
  • 堆:堆区的空间是不连续的,这是因为操作系统是用链表的形式存储空闲内存地址的,而且系统内有一个记录空闲内存地址的链表,所以在我们使用malloc等函数开辟内存空间时,操作系统会遍历该链表,找到第一个空间大于申请空间的堆节点(相当于一块空闲内存空间),将其从该链表中删除并分配给发送申请的程序,并且堆区的空间是要远大于栈区的。

存储内容的区别:

  • 栈:存储函数调用时的参数,局部变量等。执行程序时,首先调用main函数,入栈的是主函数后的下一条将要执行的语句,然后是函数参数,一般来说参数是从右往左入栈的,然后是函数体内定义的局部变量,要注意函数内static修饰的变量是静态局部变量,是不会入栈的,函数调用完后,局部变量出栈,然后是参数,最后是函数后下一条可执行语句的地址,程序也直接跳转至该处,符合数据结构中栈的“先进后出”的规则,一次完整的函数调用就是栈帧。
  • 堆:堆中具体存放的内容由程序员自己决定,我们需要使用较大内存空间时,往往会用到栈,对于大多数系统,会在这块的内存空间中的首地址处记录本次分配的大小,这样代码中的delete或free语句就能够正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会将多余的那部分重新放入空闲链表中。

执行效率的不同:

  • 栈:函数调用时,系统自动为其分配栈空间,但是不被程序员自由控制,可操作性不强,函数调用完后,栈空间自动释放,
    生命周期短,总结来说就一点,速度快!
  • 堆:堆上开辟空间的大小由程序员自己决定,而且使用起来比较方便,但是!使用完后一定要记得手动释放空间!释放玩空间后一定要记得将指向该空间的指针置空!

内存碎片问题:

  • 堆:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。
  • 栈:对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出,详细的可以参考数据结构。
  • 所以通常情况下我们主张使用栈,而不是堆,但有时候需要大量的分配空间, 还是用堆好一些,具体情况具体对待

存储效率的不同(摘录自某大佬,了解了解就好):
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
第一种在读取时直接就把字符串中的元素读到寄存器cl中,而第二种则要先把指针值读到
edx中,再根据edx读取字符,显然慢了。

小结
  1. 栈空间由操作系统分配,速度快,生命周期短;堆空间由程序员手动开辟,速度慢,使用方便
  2. 栈空间远小于堆空间
  3. 栈内存放的是局部变量,函数参数,函数方法;堆内存放的内容由程序员自己决定
  4. 栈区是连续的地址空间。而堆区是不连续的
  5. 通常情况下推荐使用栈,需要大量分配空间时,推荐使用堆
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值