然而,除此之外,它们在计算机的内存中也扮演着不同的角色。
堆(图片来自 GeeksforGeeks)
栈(图片来自 GeeksforGeeks)
在计算机中,内存的用途大致可以分为四个方面:
堆是为动态分配预留的内存空间。
和栈不一样,从堆上分配和重新分配块没有固定模式,你可以在任何时候分配和释放它。
堆包含一个链表来维护已用和空闲的内存块。在堆上新分配(用 new 或者 malloc)内存是从空闲的内存块中找到一些满足要求的合适块,这个操作会更新堆中的块链表。这些元信息也存储在堆上,经常在每个块的头部一个很小的区域。
栈是为执行线程留出的内存空间。
栈帧:也叫过程活动记录,是编译器用来实现函数调用过程的一种数据结构。
package main
func A() {
// ...
B()
}
func B() {
// ...
}
func main() {
A()
}
在上述代码片段中,main()
函数调用了函数 A()
,函数 A()
又调用了函数 B()
。执行过程如下:
main()
函数开始执行:将自己的栈帧压入栈main()
函数调用函数 A()
:将函数 A()
的栈帧压入栈A()
函数调用函数 B()
:将函数 B()
的栈帧压入栈B()
函数执行完毕,从栈顶弹出 B()
的栈帧,此时 A()
的栈帧被暴露在栈顶,处理器能根据其中的返回地址跳回 A()
的代码区继续执行代码A()
函数执行完毕,从栈顶弹出 A()
的栈帧,此时 main()
函数的栈帧被暴露在栈顶,处理器根据其中的返回地址跳回 main()
的代码区继续指定代码栈要受到内存块的限制,不断的函数嵌套或为局部变量分配太多的空间,可能会导致栈溢出。也就是我们常说「递归导致栈溢出」的原因了。
[1]
堆: https://www.geeksforgeeks.org/heap-data-structure/
[2]
栈: https://www.geeksforgeeks.org/stack-data-structure/