深度理解程序内存分区中的栈空间和堆空间

:由操作系统自动分配释放,用于存放函数的参数值、局部变量等。它的的操作方式类似于数据结构中的栈,都是后进先出。例如:

int main()
{
    int a;//栈
    char arr[] = "abcd";//栈
    char *p;//栈
}

函数中定义的局部变量按照先后定义的顺序依次压入栈中,栈的内存伸展方向是向下的,即由高到低,因此后定义的变量地址要低于先定义的变量地址。栈中存储的数据的生命周期随着函数的执行完成而结束。

堆:由程序员分配释放,若程序员不释放,程序结束是由OS进行回收,它的分配方式类似于链表。

int main()
{
    //C语言中使用malloc函数申请
    char* p1 = (char*)malloc(5);

    //使用free函数释放
    free(p1);

    //C++中用new运算符申请空间
    char* p2 = new char[10];
    
    //使用delete运算符释放
    delete[] p2;

}

p1和p2所指的的空间都是存在于堆的。堆的内存地址生长方向是向上的,即由低到高。但值得注意的是:后申请的内存空间不一定在先申请的内存空间的后面,即p2指向的地址并不一定大于p1所指向的地址。原因在于,先申请的内存空间一旦被释放,后申请的内存空间则会利用先被释放的内存,从而导致先后分配的内存空间在地址上不存在先后关系。堆中存储的数据若为释放,其生命周期与程序的生命周期相等。

另外补充一下:堆上内存空间的分配过程,首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个大于所申请空间的堆节点,然后将该节点从空闲节点链表中删除,并将该节点的空间分配给程序。对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,通过这种方式,代码中的delete语句才能正确地释放本内存空间。由于找到的堆节点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空间链表。

堆和栈的区别

1.管理方式不同。栈由操作系统自动分配释放,不需要我们手动控制;堆的申请和释放工作由程序员控制,因此容易产生内存泄漏。

2.空间大小不同。栈的大小一般只有8~10M,而堆有几个G。

3.生长方向不同。栈的生长方向向下,内存的地址由高到低,堆的生长方向向上,内存的地址由低到高。

4.分配方式不同。堆时动态分配的;栈有两种分配方式:静态分配和动态分配。静态分配是由操作系统完成,比如局部变量的分配。动态分配由malloc函数进行分配,但是栈的动态分配和堆是不同的,栈的动态分配是由操作系统进行释放,不需要我们手动释放。

5.分配效率不同。栈由操作系统自动分配,会在硬件层级对栈提供支持。分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制比较复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈低得多。

由此可见,堆和栈相比,由于大量malloc()/free()或new/delete的使用,容易造成大量的内存碎片。栈相比于堆,在程序中应用较为广泛,最常见的函数调用过程由栈来实现,函数返回地址、实参和局部变量都采用栈的方式存放。虽然栈有众多的好处,但是和堆相比不是那么灵活,有时候分配大量的内存空间任然需要用堆。总之无论是堆还是栈,在内存使用时都要防止非法越界。

 

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值