在C/C++程序里,内存分为栈、堆、全局区等不同区域。栈内存由系统自动分配回收,大小有限;而堆内存交给程序员自主掌控,运行时按需申请、手动释放。
堆内存灵活强大,但一旦管理不当,就会出现内存泄漏、野指针、程序崩溃。本次分享,我们就完整梳理堆内存从申请、使用到释放的全过程。
PPT大纲
- 栈内存 vs 堆内存
-
栈:函数内局部变量,自动分配自动回收,空间小,大小编译期基本确定
-
堆:手动申请,生命周期由开发者决定,空间大,运行时确定大小
-
什么时候必须用动态堆内存?
- C语言堆内存操作:malloc / calloc / realloc / free
-
malloc(size_t size) :分配原始内存,不初始化,失败返回NULL
-
calloc(size_t num, size_t size) :分配num个大小为size的内存,初始化为0
-
realloc(void* ptr, size_t new_size) :对已有堆内存扩容/缩容,可能移动内存地址
-
free(void* ptr) :释放堆内存,注意:free之后指针不会自动置空
-
代码示例 + 编码要点:必须检查返回值、不能free栈地址
- C++堆内存操作:new / delete
-
new :分配堆内存 + 调用构造函数初始化对象
-
delete :调用析构函数 + 释放堆内存
-
new\[\] / delete\[\] :对象数组的动态分配释放,必须成对使用
-
核心差异:malloc只分配裸内存,new会执行对象构造逻辑
-
堆内存使用的常见错误
-
内存泄漏:申请堆内存,忘记free/delete
-
野指针:内存释放后继续访问原指针
-
重复释放:同一块堆内存多次free/delete
-
API混用:malloc分配,delete释放(错误)
-
越界读写:访问超出分配的内存范围
-
现代C++优化思路:RAII与智能指针
-
RAII:资源获取即初始化,利用对象生命周期自动释放资源
-
std::unique_ptr 、 std::shared_ptr :自动释放堆内存,降低手动管理风险
-
智能指针不是万能,依然存在循环引用等问题
- 代码演示 + 内存问题排查工具
-
正常申请释放示例
-
错误案例演示(泄漏、野指针)
-
内存检测工具:Valgrind、VS内存诊断
- 堆内存的完整生命周期:申请 → 使用 → 释放。
手动管理内存,既是C/C++高性能的来源,也是bug高发区。优先养成规范,现代C++尽量使用智能指针减少手动操作。
演示代码示例
cpp
#include <iostream>
#include <cstdlib> // malloc free
#include <memory> // unique_ptr
using namespace std;
void c_malloc_demo()
{
int* p = (int*)malloc(sizeof(int));
if (p == nullptr) return;
*p = 100;
cout << *p << endl;
free(p);
p = nullptr;
}
void cpp_new_demo()
{
int* p = new int(200);
cout << *p << endl;
delete p;
p = nullptr;
}
void smart_ptr_demo()
{
unique_ptr<int> p(new int(300));
cout << *p << endl;
// 离开作用域自动释放,无需手动delete
}
int main()
{
c_malloc_demo();
cpp_new_demo();
smart_ptr_demo();
return 0;
}