作者:求一个demo
版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处
内容通俗易懂,没有废话,文章最后是面试常问内容 (建议通过标题目录学习)
废话不多说,我们直接开始------>>>>>>

一、内存泄漏
1、定义:指程序在动态分配内存后,无法释放已经已经分配的内存。
2、产生原因:
①忘记调用delete或delete[]释放内存。
②异常 导致内存释放代码未执行。
③指针被重新赋值前没有释放原内存。
3、示例:
cpp
// 示例1: 基本内存泄漏
void memoryLeak1() {
int* ptr = new int(10); // 分配内存
// 忘记delete
// delete ptr;
}
// 示例2: 异常导致的内存泄漏
void memoryLeak2() {
int* ptr = new int(20);
throw std::runtime_error("Oops"); // 抛出异常
delete ptr; // 永远不会执行
}
// 示例3: 指针重赋值导致泄漏
void memoryLeak3() {
int* ptr = new int(30);
ptr = new int(40); // 原内存泄漏
delete ptr; // 只释放了第二个分配的内存
}
4、危害:
①程序内存占用的越来越多。
②长时间运行可能导致内存耗尽。
③性能下降。
5、解决方案:
①使用智能指针(unique_ptr、shared_ptr)。
②确保每个new都有delete。
③RAII原则(在对象的构造中获取资源,在对象的析构中释放资源)。
④编写异常安全代码(保证程序异常时,能正确释放资源)(try-catch)。
二、野指针
1、定义:指向已经释放或无效内存的指针。
2、产生原因:
①指针指向的对象已被释放。
②指针未初始化。
③指针指向的局部变量 已经超出作用域。
3、示例:
cpp
// 示例1: 指向已释放内存
void danglingPointer1() {
int* ptr = new int(100);
delete ptr; // 释放内存
*ptr = 200; // 危险!ptr现在是野指针
}
// 示例2: 指向局部变量
int* danglingPointer2() {
int local = 300;
return &local; // 返回局部变量的地址
} // local超出作用域,指针变为野指针
// 示例3: 未初始化指针
void danglingPointer3() {
int* ptr; // 未初始化
*ptr = 400; // 危险!访问随机内存地址
}
4、危害:
①访问野指针导致未定义行为。
②可能造成程序崩溃。
③可能访问其他数据。
④可能造成信息泄漏。
5、解决方案:
①释放内存后将指针置空。
②使用智能指针。
③初始化所有指针。
④避免返回局部变量的指针/引用。
cpp
// 安全使用指针
void safePointer() {
// 方案1: 使用智能指针
auto smartPtr = std::make_unique<int>(500);
// 方案2: 释放后置nullptr
int* ptr = new int(600);
delete ptr;
ptr = nullptr; // 现在访问ptr会引发明确错误
// 方案3: 使用引用代替指针
int value = 700;
int& ref = value; // 引用比指针更安全
}
三、内存泄漏与野指针检测工具
1、常用工具:
①Valgrind(当程序在 Valgrind 环境下运行时,Valgrind 会对程序的内存操作进行拦截和监控。它会模拟一个虚拟的 CPU 环境,跟踪每一次内存分配和释放操作,记录内存的使用情况)(linux/macOS)。
cpp
valgrind --leak-check=full ./your_program
②AddressSanitizer(gcc)。
cpp
gcc -fsanitize=address -g your_program.c -o your_program
③Dr.Memory(Windows/linux)。
④Visual Studio Debugger (Windows)。
四、最佳操作规范
1、优先使用智能指针,而不是裸指针:
①unique_ptr用于独占所有权。
②shared_ptr用于共享所有权。
③weak_ptr用于打破循环引用。
2、遵循RAII原则:
①资源获取后立马初始化。
②构造函数获取资源,析构函数释放资源。
3、避免手动内存管理:
①使用标准库容器(vector、string等),代替动态数组。
②使用对象而非指针。
4、异常安全编程:
①确保异常发生时,资源能正确释放。
5、代码规范:
①每个new对应一个delete。
②释放后立刻将指针置为nullptr。
③避免返回裸指针。
五、内存泄漏与野指针对比
①定义上:内存泄漏是指分配的内存无法被释放;野指针是指指向无效内存的指针。
②原因上:内存泄漏是指忘记delete/异常/指针重赋值;野指针是指对象已释放/返回局部变量/未初始化。
③危害上:内存泄漏会导致内存耗尽/性能下降;野指针导致未定义/崩溃/信息泄漏。
④检测上:都是使用Valgrind/AddressSanitizer。
⑤解决方法上:内存泄漏可以使用RAII原则/智能指针;野指针可以 指针都初始化/智能指针/使用引用。
六、校招面试常问内容
1、什么是内存泄漏?危害是什么?
(1)内存泄漏:程序失去对内存的掌控,导致无法释放内存。
(2)危害:
①程序内存占用持续增长。
②内存可能逐渐被耗尽。
③性能下降,可能导致程序崩溃。
2、列举几种导致内存泄漏的场景?
①new之后忘记delete。
②异常发生在delete代码之前,导致delete被跳过。
③原内存丢失。
cpp
void leak3() {
int* p = new int(30);
p = new int(40); // 原内存泄漏
delete p; // 只释放第二个
}
3、如何避免内存泄漏?
①使用智能指针。
②编写异常 释放资源代码(try-catch)。
③确保每个new都有delete。
④使用RAII原则(构造获取资源,析构释放资源)。
⑤使用标准库容器(vector/string)代替动态数组。
4、什么是野指针?危害是什么?
(1)野指针:指向已释放或无效的内存。
(2)危害:
①未定义行为。
②导致程序崩溃或数据损坏。
③导致信息泄露。
5、野指针典型场景?
①delete释放后仍旧使用释放内存的指针。
②返回局部变量地址。
6、如何避免野指针?
①使用智能指针。
②delete释放资源后置nullptr。
③使用引用代替指针。
最后,如有不足和错误的地方,期待私信指正!
