C++中内存泄漏指的是程序动态分配的内存在使用完毕后没有被正确释放,导致这部分内存无法被再次使用的问题。内存泄漏会逐步消耗系统可用内存,对程序的稳定运行造成威胁。

C++ 内存泄漏的常见类型
1. 堆内存泄漏
这是最常见的内存泄漏类型,通常是因为使用new、new[]分配了堆内存,却没有对应使用delete、delete[]释放。比如下面的代码就会出现堆内存泄漏:
#include <iostream>
void func() {
// 使用new分配堆内存,没有释放
int* p = new int(10);
// 函数结束,p指针销毁,但指向的堆内存没有被释放,造成泄漏
}
int main() {
func();
return 0;
}2. 资源泄漏
除了堆内存,程序申请的其他系统资源如果没有正确释放也会造成泄漏,比如文件句柄、网络连接、数据库连接等。例如打开文件后没有关闭:
#include <fstream>
void readFile() {
std::ifstream file("test.txt");
// 读取文件内容后没有调用file.close(),虽然析构函数会关闭,但如果提前返回可能出问题
// 若文件打开失败没有处理,也可能造成资源占用
}3. 隐式内存泄漏
这类泄漏比较隐蔽,通常是程序在运行过程中不断分配内存,但是释放的时机过晚或者释放逻辑有缺陷,导致内存占用逐步升高。比如容器不断插入元素但没有清理,或者缓存机制没有设置过期策略。
#include <vector>
void addData(std::vector<int>& vec) {
// 每次调用都插入新元素,没有清理逻辑,长期运行会占用大量内存
for (int i = 0; i < 1000; ++i) {
vec.push_back(i);
}
}4. 循环引用导致的内存泄漏
当使用智能指针时,如果两个对象互相持有对方的shared_ptr,会形成循环引用,导致引用计数无法降为0,内存无法释放。
#include <memory>
class B; // 前置声明
class A {
public:
std::shared_ptr<B> b_ptr;
};
class B {
public:
std::shared_ptr<A> a_ptr;
};
void test() {
auto a = std::make_shared<A>();
auto b = std::make_shared<B>();
a->b_ptr = b;
b->a_ptr = a;
// 函数结束,a和b的引用计数都是1,无法释放,造成内存泄漏
}C++ 内存泄漏的后果
- 内存占用持续升高:程序运行时间越长,泄漏的内存越多,可用内存不断减少,最终可能导致系统内存不足。
- 程序性能下降:内存不足时系统会频繁进行内存交换,把数据换到磁盘上,导致程序运行速度明显变慢。
- 程序崩溃:当可用内存被耗尽,程序再申请内存时会失败,可能触发
bad_alloc异常,或者直接因为内存访问错误崩溃。 - 系统不稳定:如果泄漏的是系统资源,比如文件句柄耗尽,会导致程序无法打开新文件,甚至影响同系统下其他程序的正常运行。
- 隐蔽的运行时错误:部分内存泄漏不会立刻表现出问题,但是在特定场景下才会触发错误,增加问题排查的难度。
如何减少内存泄漏
开发者可以尽量使用智能指针管理动态内存,避免手动调用new和delete;对于申请的资源,使用RAII机制封装,确保资源在对象析构时自动释放;定期使用内存检测工具比如Valgrind、AddressSanitizer排查程序中的内存泄漏问题。