-
Notifications
You must be signed in to change notification settings - Fork 13
Cpp面试
benhao edited this page Jun 1, 2025
·
5 revisions
在 C++ 中,堆(Heap) 和 栈(Stack) 是两种核心的内存分配区域,它们在生命周期、管理方式、性能和使用场景上有显著区别。
-
特点:
- 自动管理:由编译器自动分配和释放(函数结束时自动弹出)。
- 速度快:仅需移动栈指针(硬件优化)。
- 大小固定:通常较小(默认 1-8 MB,依赖系统和编译器)。
- 局部性:存储函数参数、局部变量、返回地址等。
- 连续内存:内存地址连续分配(高效缓存利用)。
-
示例:
void foo() { int a = 10; // a 在栈上 char buffer[256]; // buffer 在栈上 } // 函数结束,a 和 buffer 自动释放
-
限制:
- 大对象(如巨型数组)可能导致栈溢出。
- 生命周期仅限于作用域内(无法跨函数传递所有权)。
-
特点:
-
手动管理:需显式分配(
new
/malloc
)和释放(delete
/free
)。 - 速度慢:需搜索可用内存块(可能触发系统调用)。
- 空间大:仅受系统可用内存限制(GB 级别)。
- 全局性:可在任何地方访问(通过指针)。
- 非连续内存:动态分配(可能产生内存碎片)。
-
手动管理:需显式分配(
-
示例:
void bar() { int* p = new int(42); // 堆上分配 int std::vector<int>* vec = new std::vector<int>(1000); // 堆上分配对象 // ... 使用 p 和 vec ... delete p; // 手动释放 delete vec; }
-
风险:
-
内存泄漏:忘记
delete
。 - 悬空指针:访问已释放内存。
- 碎片化:频繁分配/释放导致内存利用率降低。
-
内存泄漏:忘记
特性 | 栈(Stack) | 堆(Heap) |
---|---|---|
管理方式 | 编译器自动管理 | 程序员手动管理(new /delete ) |
速度 | 极快(移动栈指针) | 较慢(搜索可用内存) |
大小限制 | 小(默认 MB 级) | 大(仅限系统内存) |
生命周期 | 作用域内(函数结束即释放) | 直到显式释放 |
内存布局 | 连续地址 | 碎片化(非连续) |
使用场景 | 局部变量、小型数据 | 大对象、动态数据结构、跨函数共享 |
错误风险 | 栈溢出 | 内存泄漏、悬空指针、碎片化 |
#include <iostream>
#include <vector>
void stackExample() {
int x = 5; // 栈分配
std::vector<int> arr(100); // arr 对象在栈上,内部数据在堆上
} // x 和 arr 自动释放(arr 的析构函数释放内部堆内存)
void heapExample() {
int* y = new int(10); // 堆分配
std::vector<int>* vec = new std::vector<int>(1000); // 对象本身在堆上
// ... 使用 y 和 vec ...
delete y; // 必须手动释放!
delete vec; // 否则内存泄漏
}
int main() {
stackExample(); // 安全:无内存泄漏
heapExample(); // 风险:若忘记 delete 则泄漏
return 0;
}
-
优先使用栈:
- 小型对象和局部变量。
- 避免栈溢出(避免巨型栈分配)。
-
智能指针管理堆:
#include <memory> void safeHeap() { auto ptr = std::make_unique<int>(30); // 自动释放 auto arr = std::make_shared<std::vector<int>>(100); // 引用计数 } // 无需 delete
-
避免裸指针:用
std::vector
替代动态数组,用std::string
替代char*
。 -
栈溢出防范:
- 递归时控制深度。
- 大对象改用堆(如
std::vector
存储大量数据)。
-
Q:
new
和malloc
的区别?
new
调用构造函数,malloc
仅分配内存;delete
调用析构函数,free
仅释放内存。 -
Q:如何检测内存泄漏?
使用工具:Valgrind(Linux)、AddressSanitizer(GCC/Clang)、Visual Studio 诊断工具。 -
Q:对象成员存储在堆还是栈?
对象本身的位置决定其成员位置:class MyClass { int a; // 若 MyClass 在栈上,则 a 在栈上 int* b; // b(指针)在栈上,但 *b 指向堆内存 };
总结:
- 栈:自动、快速、安全,适合小型临时数据。
- 堆:灵活、大容量,需谨慎管理,适合动态生命周期数据。
-
现代 C++ 准则:用智能指针和容器(如
std::vector
)减少裸堆操作!