堆与栈的区别详解
扫描二维码
随时随地手机看文章
堆(heap)和栈(stack)是在计算机中常用的两种数据结构。它们具有不同的特点和用途,对于程序员来说,了解堆和栈的区别是非常重要的。
首先,堆和栈的内存分配方式不同。堆是由程序员手动分配和释放的,而栈是由操作系统自动分配和释放的。在堆中,使用malloc()或new关键字来分配内存空间,通过free()或delete关键字来释放内存。在栈中,变量的内存分配和释放是由编译器自动完成的,无需程序员干预。
其次,堆和栈的大小不同。栈的大小是固定的,一般在程序运行时就确定了,而堆的大小是动态增长的,可以根据需要动态地申请和释放内存空间。
另外,堆和栈的数据访问方式也有所不同。在堆中,数据的访问是通过指针来实现的,需要通过指针寻址来访问和操作数据。而在栈中,数据的访问是通过变量名来实现的,可以直接访问和操作变量。
堆和栈还有一个重要的区别是数据的生命周期。在堆中,数据的生命周期可以很长,需要手动释放内存,否则会导致内存泄漏。而在栈中,变量的生命周期是由其所在的作用域来决定的,一旦离开作用域,变量就会被自动释放。
在使用堆和栈时,还需要考虑到一些因素。堆是动态分配的,所以分配和释放内存的速度较慢,并且可能会造成内存碎片的问题。栈是静态分配的,所以分配和释放内存的速度非常快,但是栈的大小是有限的,如果将大量的数据存储在栈中,可能会导致栈溢出的问题。
在实际应用中,堆和栈都有各自的使用场景。堆主要用于动态分配大量的内存空间,适合存储复杂的数据结构,比如树、图等。栈主要用于保存函数的局部变量、参数值等,适合存储简单的数据类型。
总结起来,堆和栈在内存分配方式、大小、数据访问方式、生命周期等方面有着不同的特点。程序员需要根据具体的需求,选择合适的数据结构和内存分配方式,以提高程序的性能和效率
堆与栈的区别:空间分配栈操作系统自动分配释放,堆由程序员分配释放;缓存方式,栈使用的是一级缓存,堆则是存放在二级缓存;堆栈数据结构区别;管理方式不同;生长方式不同;空间大小不同;内存速率不同;存储内容不同;分配方式不同。
1、堆栈空间分配区别
栈(操作系统):由操作系统(编译器)自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
堆(操作系统): 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
2、堆栈缓存方式区别
栈使用的是一级缓存, 它们通常都是被调用时处于存储空间中,调用完毕立即释放。
堆则是存放在二级缓存中,生命周期由虚拟机的垃圾回收算法来决定(并不是一旦成为孤儿对象就能被回收)。所以调用这些对象的速度要相对来得低一些。
3、堆栈数据结构区别
堆(数据结构):堆可以被看成是一棵树,如:堆排序。
栈(数据结构):一种先进后出的数据结构。
4.管理方式不同
堆是由程序员通过 调用系统库函数来管理内存,所以管理不力 就会出现常说的内存泄漏
栈是由计算机系统分配内存 而且系统有专门的寄存器存储栈指针。
5.生长方式不同
堆是向高地址扩展 也就是常说的向上生长。是不连续的内存区域。
栈是向低地址扩展 也就是常说的向下生长。 是连续的内存区域。
6.空间大小不同
堆的大小 可以高达 4G 在32位Linux里系统有效的虚拟内存也有3.2G
栈的大小 一般是 1M ~10M 不等(和堆相差很多)。
7.内存速率不同
栈的内存速率较快。前面说了 栈是系统分配内存 ,而且有这FILO的出栈顺序 所以栈的内存速率快些。
堆 因为是程序员分配内存 ,而且是由C/C++函数库提供的。而且机制比较复杂,为了找打到一块合适大小的内存区域 会挨个遍历。所以耗时也就比较多些。
8.存储内容不同
栈在函数调用时,首先压入主调函数中下条指令(函数调用语句的下条可执行语句)的地址,然后是函数实参,然后是被调函数的局部变量。本次调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的指令地址,程序由该点继续运行下条可执行语句。
堆通常在头部用一个字节存放其大小,堆用于存储生存期与函数调用无关的数据,具体内容由程序员安排。
(其实我自己的理解是栈有自己的出栈方式FILO 所以局部调用结束后就直接出栈了,然后进行其他没出栈的操作处理。而堆是先存需要的内存大小,然后后面的就交给创建者自己处理了)
9.分配方式不同
栈可静态分配或动态分配。静态分配由编译器完成,如局部变量的分配。动态分配由alloca函数在栈上申请空间,用完后自动释放。
堆只能动态分配且手工释放。(堆就好比OC语言里的MRC,而OC里的ARC就是苹果帮我们处理的MRC)
1.3 堆与栈区别
堆与栈实际上是操作系统对进程占用的内存空间的两种管理方式,主要有如下几种区别:
(1)管理方式不同。
栈由操作系统自动分配释放,无需我们手动控制;堆的申请和释放工作由程序员控制,容易产生内存泄漏;
(2)空间大小不同。
每个进程拥有的栈大小要远远小于堆大小。理论上,进程可申请的堆大小为虚拟内存大小,进程栈的大小 64bits 的 Windows 默认 1MB,64bits 的 Linux 默认 10MB;
(3)生长方向不同。
堆的生长方向向上,内存地址由低到高;栈的生长方向向下,内存地址由高到低。
(4)分配方式不同。
堆都是动态分配的,没有静态分配的堆。栈有 2 种分配方式:静态分配和动态分配。静态分配是由操作系统完成的,比如局部变量的分配。动态分配由alloca()函数分配,但是栈的动态分配和堆是不同的,它的动态分配是由操作系统进行释放,无需我们手工实现。
(5)分配效率不同。
栈由操作系统自动分配,会在硬件层级对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++提供的库函数或运算符来完成申请与管理,实现机制较为复杂,频繁的内存申请容易产生内存碎片。显然,堆的效率比栈要低得多。
(6)存放内容不同。
栈存放的内容,函数返回地址、相关参数、局部变量和寄存器内容等。当主函数调用另外一个函数的时候,要对当前函数执行断点进行保存,需要使用栈来实现,首先入栈的是主函数下一条语句的地址,即扩展指针寄存器的内容(EIP),然后是当前栈帧的底部地址,即扩展基址指针寄存器内容(EBP),再然后是被调函数的实参等,一般情况下是按照从右向左的顺序入栈,之后是被调函数的局部变量,注意静态变量是存放在数据段或者 BSS 段,是不入栈的。出栈的顺序正好相反,最终栈顶指向主函数下一条语句的地址,主程序又从该地址开始执行。堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来填充的。
从以上可以看到,堆和栈相比,由于大量 malloc()/free() 或 new/delete 的使用,容易造成大量的内存碎片,并且可能引发用户态和核心态的切换,效率较低。栈相比于堆,在程序中应用较为广泛,最常见的是函数的调用过程由栈来实现,函数返回地址、EBP、实参和局部变量都采用栈的方式存放。虽然栈有众多的好处,但是由于和堆相比不是那么灵活,有时候分配大量的内存空间,主要还是用堆。
无论是堆还是栈,在内存使用时都要防止非法越界,越界导致的非法内存访问可能会摧毁程序的堆、栈数据,轻则导致程序运行处于不确定状态,获取不到预期结果,重则导致程序异常崩溃,这些都是我们编程时与内存打交道时应该注意的问题。
2.数据结构中的堆与栈
数据结构中,堆与栈是两个常见的数据结构,理解二者的定义、用法与区别,能够利用堆与栈解决很多实际问题。
2.1 栈简介
栈是一种运算受限的线性表,其限制是指只仅允许在表的一端进行插入和删除操作,这一端被称为栈顶(Top),相对地,把另一端称为栈底(Bottom)。把新元素放到栈顶元素的上面,使之成为新的栈顶元素称作进栈、入栈或压栈(Push);把栈顶元素删除,使其相邻的元素成为新的栈顶元素称作出栈或退栈(Pop)。这种受限的运算使栈拥有“先进后出”的特性(First In Last Out),简称 FILO。
栈分顺序栈和链式栈两种。栈是一种线性结构,所以可以使用数组或链表(单向链表、双向链表或循环链表)作为底层数据结构。使用数组实现的栈叫做顺序栈,使用链表实现的栈叫做链式栈,二者的区别是顺序栈中的元素地址连续,链式栈中的元素地址不连续。