在 C语言中,程序运行时会存在 栈 和 堆 两种不同的内存分配方式。
接下来,我们从 内存分配方式 、内存地址增长 和 碎片 三个方面来对比 栈 和 堆。
内存分配方式
栈:系统自动分配和释放,主要存放程序中的实际参数和局部变量。
堆:程序员自己分配和释放,可以动态拓展和搜索的内存空间,程序调用 malloc、new、free 之类的函数堆大小会变化。
内存地址增长
栈:向着内存地址减小的方向增长,由内存的高地址向低地址方向增长。
堆:向着内存地址增长方向增长,从内存地址的低地址向高地址方向增长。
碎片
栈:因为是连续分配的空间,所以没有碎片问题。
堆:频繁的 malloc 或 free 会造成内存空间的不连续。
示例
下面是一个 C++ 代码的例子:
# include <iostream>
using namespace std;
void stack_example(){
int stack_var = 10; // 局部变量,在栈中分配内存
cout << "Stack variable: " << stack_var << endl;
}
void heap_example(){
int * heap_var = new int(20); // new,在堆中分配内存
cout << "Heap variable:" << *heap_var << endl;
delete heap_var; // 释放堆内存
}
int main(){
stack_example();
heap_example();
return 0;
}
注意,当你在堆上分配内存时,需要使用完成后进行释放,否则可能会导致内存泄露的问题。
内存泄露就是指,你向程序申请内存后没有归还给系统,那么这个对象就会一直占用这块内存。
拓展:静态变量
全局静态变量和局部静态变量都是存储在静态存储区之中的。
区别就是,局部静态变量会在函数销毁时依旧驻留在内存中,直到程序结束。
但是,如果是动态分配的静态变量,它需要在多个内存之间共享并保存值,就会存放在堆区,这样它的生命周期会伴随程序的整个过程。
比如,我们可以看一个 C++ 的例子:
# include <iostream>
using namespace std;
void allocate_static(){
static int* heap_var = new int(20);
cout << "Heap variable:" << *heap_var << endl;
}
int main(){
allocate_static();
return 0;
}