【C++】内存分配与释放、内存碎片、内存泄漏、栈溢出
C++内存分配方式
内存分配方式区别
特性 | 静态分配 | 栈分配 | 堆分配 |
分配时机 | 编译期 | 函数调用时 | 运行期( |
释放方式 | 自动释放 | 函数结束自动释放 | 手动 |
内存区域 | 静态存储区 | 栈 | 堆(自由存储区) |
大小灵活性 | 固定 | 固定 | 动态可调 |
分配速度 | 快 | 极快 | 较慢(需堆管理) |
作用域控制 | 全局 / 静态局部 | 函数内局部 | 程序员显式控制 |
常见问题 | 无 | 栈溢出 | 内存碎片、泄漏 |
内存碎片
内存泄漏
- 程序未释放不再使用的内存,导致可用内存逐渐减少
- 常见原因:
- 忘记调用delete或者free()
- 异常导致未执行释放代码(new后抛出异常)
- 循环引用(shared_ptr互相引用)
- 指针被覆盖:
int* p = new int; p = new int;
(第一个new
泄漏)。- 检查工具:
- Valgrind(Linux):通过动态二进制插装检测内存泄漏,支持
new
/malloc
等分配方式- Visual Studio 调试工具:利用 “内存诊断” 功能追踪堆分配,定位泄漏位置。
- VLD :Windows CRT内存跟踪
- 解决方案:
- 显式释放动态分配的内存
- 使用智能指针或容器自动管理资源
- 配对使用内存分配与释放函数
- 分配内存后及时初始化,未初始化的内存可能包含垃圾值
- malloc结合memset函数手动初始化
- calloc或值初始化(calloc自动初始化为0,new可通过()初始化
- 释放结构化元素时优先释放子内存:结构体或类中包含动态内存的指针成员时,直接释放父对象会导致子内存无法访问,从而泄露
- 在析构函数中集中释放:类对象应在析构函数中释放所有成员管理的资源
- 自底向上释放:先释放深层嵌套的资源,再释放外层结构