面试被问堆栈的区别,很多人答一句「一个自动分配,一个手动申请」就没了下文。真写代码时,这个差别会直接影响程序会不会崩、跑得快不快。
栈跟着函数走,返回就回收
栈主要放局部变量、函数参数和返回地址。函数一调用,栈指针往下挪一块;函数返回,指针退回去,内存自动回收,分配本身只是改一个寄存器,速度极快。栈是每个线程私有的,大小有上限,Windows 下线程栈默认一般 1MB,Linux 常见 8MB,可以用 ulimit -s 查看,递归写深了报 stack overflow 就是把这块钱用完了。局部数组开太大,几百 KB 就可能把栈撑爆。
堆要自己申请,也得自己还
C 里用 malloc 和 free,C++ 里用 new 和 delete。堆的空间大,生命周期由程序员控制,可以在两个函数之间传来传去,缺点是分配慢,频繁申请释放会产生内存碎片。忘了 free 就是内存泄漏,释放两次或者释放后继续用,程序可能直接崩溃,C++ 一般用智能指针和 RAII 把释放交给析构函数。32 位程序可用地址空间一般 2GB 到 3GB,64 位宽松得多。
数据结构的栈和堆是另一套概念
数据结构里的栈是后进先出,函数调用、括号匹配、撤销操作都用它。堆是一棵完全二叉树,常用来做优先队列,C++ 的 priority_queue 底层就是堆。这里的堆和内存里的堆只是重名,别混在一起讲。堆排序就是利用这个结构,建堆后反复取堆顶。
写代码时怎么选
小而短命的变量放栈上,大数组、缓存、需要跨函数存活的对象放堆上。栈空间紧张时,把大数组挪到堆上往往就能解决崩溃;嵌入式环境栈更小,几百字节的局部数组都可能出问题。Java 和 C# 的对象多数分配在堆上,栈里放的是引用。C++ 的 vector 数据放堆上,对象本身仍可在栈上。
记住堆栈的区别,落到一句话:栈快但短,堆慢但自由。答题时把自动与手动、空间大小、速度、生命周期这几点说全,基本就到位了。面试再追问,就从分配方式、速度、大小、生命周期四个维度答。