1. 分配方式
- 栈内存分配:由编译器自动分配和释放,函数内定义的局部变量(非动态分配)都在栈上分配内存。例如:
void func() {
int num = 10; // num 在栈上分配内存
}
- 堆内存分配:需要程序员手动使用
new
(C++)或 malloc
(C兼容)等操作符来分配内存。例如:
int* ptr = new int(10); // 在堆上分配一个 int 类型的内存空间,并初始化为 10
2. 生命周期
- 栈内存分配:其生命周期与所在函数或代码块紧密相关。当函数执行结束或代码块结束时,栈上的变量会自动被销毁,内存被释放。例如:
void func() {
int num = 10;
} // 函数结束,num 的内存被自动释放
- 堆内存分配:其生命周期取决于程序员手动释放。使用
new
分配的内存,必须使用 delete
来释放;使用 malloc
分配的内存,必须使用 free
来释放。若不手动释放,会导致内存泄漏。例如:
int* ptr = new int(10);
// 若之后没有 delete ptr; 则会发生内存泄漏
3. 内存管理
- 栈内存分配:编译器自动管理,程序员无需手动干预内存的释放,不易出现内存泄漏问题。
- 堆内存分配:程序员负责分配和释放内存。如果忘记释放,会造成内存泄漏;多次释放同一块内存会导致程序崩溃等问题。例如:
int* ptr = new int(10);
delete ptr;
delete ptr; // 第二次释放会导致未定义行为
4. 适用场景
- 栈内存分配场景:
- 当变量的生命周期与函数执行周期相同,且占用空间较小,例如函数内的临时变量、循环变量等。比如:
void calculateSum() {
int sum = 0;
for(int i = 0; i < 10; ++i) {
sum += i;
}
// sum 和 i 都在栈上分配,函数结束自动释放
}
- 当需要快速分配和释放内存,因为栈的操作效率较高。例如频繁调用的函数内的局部变量。
- 堆内存分配场景:
- 当需要动态分配内存,且内存大小在编译时无法确定。例如,根据用户输入创建数组:
int size;
std::cin >> size;
int* arr = new int[size];
// 这里数组大小在运行时由用户输入决定,只能在堆上分配
- 当对象的生命周期需要跨越多个函数调用或代码块,需要手动控制其生命周期时。例如,在一个函数中创建对象,在另一个函数中使用并最终释放:
class MyClass {
public:
MyClass() { std::cout << "Constructor" << std::endl; }
~MyClass() { std::cout << "Destructor" << std::endl; }
};
MyClass* createObject() {
return new MyClass();
}
void useObject(MyClass* obj) {
// 使用 obj
}
void releaseObject(MyClass* obj) {
delete obj;
}
int main() {
MyClass* obj = createObject();
useObject(obj);
releaseObject(obj);
return 0;
}