Why Stack And Heap
栈 和 堆 的原始由来
对于 栈 和 堆 ,我们通常也只是知道: 栈先进后出,堆无所谓。栈占内存比较小,堆比较大。栈占内存是连续的,堆不连续。 等这样一些区别,但它们的原始由来,我们清楚吗?
一开始我也是不清楚这点的,后来有次复习 C 教程,先看的内存管理,后看的堆栈,于是一下子开窍了(我不确定我的观点是否正确,仅作参考)。
假设这样的代码:
int main() {
for(;;) {
int a = 1;
}
}
很明显,这样的代码是能够无限运行下去的。
但是,那句 int a = 1;
中的 1
肯定是有存在内存中的,那么如果这句代码无限循环运行,内存难道不应该被撑爆吗?
事实是它没有撑爆,所以,肯定有东西在帮我们回收内存。我们应该很容易就能猜到,就是编译器在帮我们做这个事情的。
所以,真实的代码其实相当于:
int main() {
for(;;) {
int a = 1;
free(a); // 不清楚该写成 free(a) 还是 free(&a), 总归就是这个意思吧
}
}
既然回收内存是编译器帮我们做的,那对称一下,分配内存应该也是编译器帮我们做的:
int main() {
for(;;) {
int *a = malloc(sizeof(int));
*a = 1;
free(a);
}
}
OK。。。编译器帮我们分配内存、回收内存,可是它是根据什么来帮我们做这些事情的呢?
作用域 。有的编程语言的作用域是函数作用域,有的是块作用域。但根据本身就是 作用域 。
于是, 栈就这么出现了 。
栈并非什么我们人类发明的概念,而是固有的。人们只是发现了栈而已。
OK, 栈 说完了,那 堆 呢?
堆 其实没啥好说的,无非就是我们有手动管理内存的需求而已。无论是因为超大对象,如果放在栈里,导致常常复制删除,大量降低性能,还是有内存数据需要被跨函数访问到,这都需要我们手动管理内存。所以, 堆 就出现了。
那根据上面的理论, 栈是编译器根据变量作用域帮我们自动管理内存的一种方式,堆是让程序员手动管理内存的方式 ,那么:
- 栈先进后出: 其实就只是变量作用域本身的概念,一个作用域包裹另一个作用域;
- 栈占内存比较小,堆比较大: 这只是常规的较好的代码实现,否则就太消耗性能了,毕竟编译器的自动内存管理并没有那么聪明,但这也并非绝对的;
- 栈占内存是连续的,堆不连续: 也只是一个较好的代码实现而已,而且因为 栈先进后出 的特性,把它实现为连续内存更是理所当然,连续内存,读取写入速度更快。
以上对于 栈 和 堆 的原始由来 的理解仅仅是个人看法,观点仅作参考。