1. 内存泄漏基础:什么是内存泄漏、内存泄漏的危害、C++内存管理模型

什么是内存泄漏?

内存泄漏,说白了就是「借了东西不还」。

你向操作系统申请了一块内存,用完之后忘了释放。这块内存就一直被占用着,谁也拿不走。程序跑得越久,漏得越多,最后系统内存被吃光,程序就崩了。

我刚开始做C++开发时,觉得这玩意儿离我很远。直到有一次,我负责的一个后台服务跑了三天后突然挂掉,查了半天才发现是一个循环里每次new了对象却没delete。嗯,从那以后我再也不敢小看内存泄漏了。

核心定义:内存泄漏是指程序中已动态分配的堆内存,由于某种原因程序未释放或无法释放,造成系统内存的浪费。

一个简单的例子

void leakyFunction() {
    int* p = new int(42);  // 申请了内存
    // 忘记 delete p;
    // 函数返回后,p 丢失,内存再也无法释放
}

这个函数每调用一次,就泄漏4个字节。看起来不多?如果它在循环里被调用一万次呢?

内存泄漏的危害

你想想看,内存泄漏就像水管漏水。一开始只是滴滴答答,没人会在意。但时间长了,后果很严重。

  • 程序变慢:内存越占越多,系统开始使用交换分区,性能断崖式下跌
  • 程序崩溃:内存耗尽,new操作抛出std::bad_alloc异常
  • 系统不稳定:一个程序把内存吃光了,其他程序也跟着遭殃
  • 难以排查:泄漏往往在特定场景下才暴露,复现困难

我曾经踩过的坑:一个Qt界面程序,用户反馈说「用着用着就卡死了」。我远程看了下,任务管理器里内存占用从50MB一路涨到2GB。最后定位到是一个定时器里不断创建QWidget却不销毁。这种泄漏最隐蔽——它不报错,只是慢慢杀死你的程序。

C++内存管理模型

要理解内存泄漏,得先搞清楚C++的内存是怎么管的。我个人习惯把内存区域分成四个部分:

内存区域 存储内容 生命周期 常见问题
栈区 局部变量、函数参数 函数执行期间 栈溢出(递归太深)
堆区 动态分配的对象 手动控制 内存泄漏、野指针
全局/静态区 全局变量、static变量 程序启动到结束 多线程竞争
代码区 程序指令 程序运行期间 一般没问题

内存泄漏主要发生在堆区。为什么呢?因为栈上的变量由编译器自动管理,函数结束就自动释放。而堆上的内存,你得自己管。

堆内存的生命周期

在C++里,堆内存的申请和释放是这样的:

// 申请
int* p = new int;        // 单个对象
int* arr = new int[10];  // 对象数组

// 释放
delete p;                // 释放单个对象
delete[] arr;            // 释放对象数组

这里有个坑:new 和 delete 要配对,new[] 和 delete[] 要配对。混用会导致未定义行为。我见过有人用 delete 去释放 new[] 出来的数组,结果程序崩溃得一塌糊涂。

避坑指南:在Qt项目中,尽量使用Qt的父对象机制。把QObject对象的父对象设置好,父对象销毁时会自动销毁子对象。这能省去大量手动管理内存的麻烦。

为什么C++容易内存泄漏?

说白了,C++给了你最大的自由度,也给了你最大的责任。不像Java有垃圾回收,C++把内存管理的缰绳完全交到你手里。

常见的泄漏场景:

  • 异常导致delete语句没执行到
  • 指针被重新赋值,原来的内存没人管了
  • 容器里存了指针,容器销毁时没遍历释放
  • 循环引用导致智能指针无法释放

知识体系总览

下面这张图,是我整理的内存泄漏知识体系。你可以把它当作整个课程的地图:

内存泄漏知识体系 什么是内存泄漏 • 动态内存未释放 • 指针丢失无法回收 • 资源句柄未关闭 • 容器元素泄漏 内存泄漏危害 • 程序性能下降 • 系统资源耗尽 • 程序崩溃 • 难以排查定位 C++内存管理模型 • 栈区自动管理 • 堆区手动管理 • 全局/静态区 • 代码区 常见泄漏场景 异常导致 delete未执行 指针被覆盖 原内存丢失 容器存指针 未遍历释放 循环引用 智能指针失效 解决方案(后续章节展开) RAII技术 智能指针 Qt父对象机制 内存检测工具

小结

内存泄漏不是「会不会遇到」的问题,而是「什么时候遇到」的问题。每个C++开发者迟早都会栽跟头。区别在于,有的人栽一次就学会了,有的人反复栽。

我个人觉得,理解内存泄漏的关键就三点:

  1. 知道它是什么——借了内存没还
  2. 知道它怎么来的——堆内存管理不当
  3. 知道它怎么防——RAII、智能指针、Qt父对象机制

后面的章节,我会带着你一步步把这些工具用起来。嗯,咱们慢慢来。

一个小建议:从现在开始,每次写new的时候,脑子里自动弹出「我什么时候delete它?」这个问题。养成这个习惯,能帮你避开80%的内存泄漏。

可可精品资料库