写C或C++程序时,你有没有遇到过程序跑着跑着越来越慢,最后直接卡死?任务管理器里一看,内存占用蹭蹭涨——十有八九,是内存泄漏在作怪。而泄漏的“罪魁祸首”,常常就是指针没管好。
指针不是锅,但不盯紧它,锅就来了
指针本身不产生内存,但它像一把钥匙,能打开堆内存的大门。new/malloc申请的内存,得靠指针记住地址;用完之后,必须用delete/free还回去。一旦忘了还、还错了、或者提前丢了指针(比如指针被赋值为NULL又没检查),那块内存就再也找不回来了。
举个常见例子:
void process_data() {
int* ptr = new int[1000];
// 做一些计算……
if (some_error) return; // ❌ 忘了delete,直接退出
delete[] ptr;
}
这个函数一出错就返回,ptr指向的1000个int永远留在堆里,下次再调用,又占一块——反复几次,内存就“漏”光了。
几个实在的防漏习惯
1. new 和 delete 写在同一层作用域里
尽量别让指针跨函数乱飞。如果非得传出去,明确谁负责释放。比如下面这样更安全:
void safe_process() {
std::unique_ptr<int[]> ptr(new int[1000]); // C++11起,自动管理
// 用ptr.get()获取原始指针干活
do_something(ptr.get());
// 函数结束,ptr自动delete[],不用手写
}
2. C语言里用封装+注释盯死生命周期
比如自己写个malloc包装函数,强制配对free,并在头文件里写清责任:
// utils.h
// 返回的buffer必须由调用方free()
char* alloc_buffer(size_t size);
// main.c
char* buf = alloc_buffer(4096);
if (buf) {
strcpy(buf, "hello");
printf("%s\n", buf);
free(buf); // ✅ 这行不能少
buf = NULL; // 防二次释放
}
3. 调试时打开工具盯一眼
Windows下用Visual Studio的诊断工具,Linux下用valgrind:valgrind --leak-check=full ./myapp
它会清楚告诉你哪行new没配delete、哪块内存彻底失联了。
别迷信智能指针,但别拒绝它
有人觉得“我手动控制才靠谱”,结果改代码时删掉一行delete就漏了;也有人一上来就堆shared_ptr,反而引发循环引用。其实,std::unique_ptr适合绝大多数单所有权场景,轻量、零开销、不共享——就像租房子只签一个租客合同,到期自动退房,省心还不打架。
内存泄漏不是玄学,是动作没做全。把指针当借条管:借多少、谁借的、还给谁、啥时候还——一条条写清楚,内存自然就稳住了。