内存泄漏
1.具体解释
1.1定义 :动态分配的内存(如通过 new
、malloc
)未被正确释放,导致程序运行期间内存占用持续增长,最终可能耗尽系统资源。
1.2常见场景
1.2.1异常抛出导致 delete
未执行:
cpp
void foo() {
int* p = new int(42);
throw std::runtime_error("Error"); // 异常抛出,p 未释放
delete p; // 不会执行
}
1.2.2循环中分配内存但未释放:
cpp
while (true) {
int* p = new int[1000]; // 每次循环分配,但未释放
}
1.2.3对象析构时未释放成员指针:
cpp
class BadExample {
int* data;
public:
BadExample() : data(new int[100]) {}
~BadExample() { /* 忘记 delete[] data; */ } // 泄漏
};
1.2影响:程序性能下降、崩溃(OOM),长期运行的服务可能因内存耗尽被系统终止
1.3防范
1.3.1使用智能指针(std::unique_ptr
、std::shared_ptr
)自动管理内存
1.3.2遵循RAII(资源获取即初始化) 原则,将资源绑定到对象生命周期
文件描述符泄漏
1.具体解释
2.1定义:打开的文件或套接字未被关闭,导致系统文件描述符耗尽(Linux 默认限制通常为 1024~65536)
2.2常见场景
2.2.1未调用 close()
或 fclose()
:
cpp
void readFile() {
FILE* f = fopen("data.txt", "r");
if (f) {
// 处理文件...
// 忘记 fclose(f); // 泄漏
}
}
2.2.2异常路径未关闭文件:
cpp
void processFile() {
int fd = open("data.txt", O_RDONLY);
if (fd == -1) return;
// 处理文件...
if (error_occurred) throw std::runtime_error("Error"); // fd 未关闭
close(fd); // 可能跳过
}
2.影响:无法打开新文件或网络连接,系统功能受限。
3.防范
2.3.1使用 RAII 封装文件操作(如 std::ifstream
、std::ofstream
)
2.3.2自定义文件句柄管理类,析构时自动关闭:
cpp
class FileHandle {
int fd;
public:
FileHandle(const char* path) : fd(open(path, O_RDONLY)) {}
~FileHandle() { if (fd != -1) close(fd); }
};
锁泄漏
1.具体解释
3.1定义:获取的锁(如互斥量 std::mutex
)未被释放,导致其他线程永久阻塞。
3.2常见场景
3.2.1未调用 unlock()
:
cpp
std::mutex mtx;
void criticalSection() {
mtx.lock();
// 处理共享数据...
// 忘记 mtx.unlock(); // 泄漏
}
3.2.2异常抛出导致锁未释放:
cpp
void riskyOperation() {
std::lock_guard<std::mutex> lock(mtx); // 正确:RAII 自动释放
// 若使用手动锁:
mtx.lock();
throw std::runtime_error("Error"); // 锁未释放
mtx.unlock();
}
2.影响:线程死锁,系统响应变慢或崩溃
3.防范
3.3.1优先使用 std::lock_guard
或 std::unique_lock
自动管理锁生命周期
3.3.2避免在持有锁时调用可能抛异常的函数。
网络资源泄漏
1.具体解释
4.1定义:未正确关闭网络连接(如套接字、数据库连接),导致资源耗尽或连接池枯竭。
4.2常见场景
4.2.1未调用 close()
或 disconnect()
4.2.2数据库连接未归还
2.影响:网络服务不可用,数据库连接数超限。
3.防范
4.3.1使用 RAII 封装网络资源(如 std::unique_ptr
自定义删除器)。
4.3.2连接池实现自动回收机制。
循环引用导致的内存泄漏
1.具体解释
5.1定义:在引用计数智能指针(如 std::shared_ptr
)中,两个对象相互引用,导致引用计数永远无法归零
5.2常见场景
cpp
struct Node {
std::shared_ptr<Node> next;
std::shared_ptr<Node> prev; // 双向循环引用
};
auto a = std::make_shared<Node>();
auto b = std::make_shared<Node>();
a->next = b;
b->prev = a; // 引用计数均为 2,离开作用域后不会释放
2.影响:内存无法回收,即使对象不再使用。
3.防范:使用 std::weak_ptr
打破循环