delete 和 free 有什么区别?
delete和free都是用来释放动态分配的内存,但它们有不同的使用方式:
- 语法:
○ delete是C++中的关键字,用于释放由new分配的对象。
○ free是C语言中的函数,通常包含在<stdlib.h>头文件中,用于释放由malloc分配的内存。 - 对象销毁:
○ 当使用 delete 释放对象内存时,C++ 编译器会自动调用对象的析构函数,释放与对象相关的资源,并执行对象的清理工作。
○ free 仅释放内存,不调用析构函数。因此,如果使用 malloc 分配了 C++ 对象的内存,需要手动调用析构函数后再调用 free。 - 数组处理:
○ 如果是数组,C++提供了delete[]来释放整个数组的内存,而C语言中仍然使用free,没有区分单个对象和数组。 - 返回值:
○ free 没有返回值,即使内存释放失败,也不会反馈任何信息。
○ delete 之后,指针会自动置为 nullptr - 类型检查:
○ delete 进行类型检查,确保删除的对象类型与 new 分配时的类型一致。
○ free 不进行类型检查,因为它只处理 void* 类型的指针。
总结来说,delete和free都是用来释放动态内存的,但它们分别用于C++和C语言中的内存管理。delete适用于C++对象,会自动调用析构函数;而free适用于C语言分配的内存,不涉及对象的析构。
什么是内存泄漏, 如何检测和防止?
- 如果程序的某一段代码在内存池中动态申请了一块内存而没有及时将其释放,就会导致那块内存一直处于被占用的状态而无法使用,造成了资源的浪费。内存泄漏并不是说物理上的消失掉了,是因为无法使用该区域,在外界看来这块内存就好像被泄漏了一样。
- 什么操作会导致内存泄漏
○ 忘记释放内存:使用 new 或 malloc 等分配内存后,没有使用 delete 或 free 释放内存。
○ 子类继承父类时,没有将基类的析构函数定义为虚函数。
○ 野指针:指针被赋值为 nullptr 或重新赋值后,丢失了对先前分配内存的引用,导致无法释放。
○ 循环引用:在使用引用计数的智能指针(如 std::shared_ptr)时,循环引用会导致引用计数永远不会归零,从而无法释放内存。
○ 使用不匹配的内存释放函数: 使用 delete 释放由 new[] 分配的内存,或使用 delete[] 释放由 new 分配的内存,这可能导致未定义行为。
○ 资源未关闭:对于文件、网络连接等资源,如果没有正确关闭,虽然不直接导致内存泄漏,但会占用系统资源,可能导致资源耗尽。 - 如何检测:使用工具如Valgrind、AddressSanitizer或Visual Studio的诊断工具来检测内存泄漏。
- 如何避免
○ 使用智能指针:优先使用 std::unique_ptr、std::shared_ptr 等智能指针来自动管理内存。
○ 确保资源释放: 对于手动分配的内存,确保在不再需要时使用 delete 或 free 释放。
○ 内存泄漏检测工具: 在开发和测试阶段,定期使用内存泄漏检测工具检查程序。
什么是野指针?如何避免?
- 什么是野指针
野指针是指“指向已经被释放的或无效的内存地址的指针”。在 C 和 C++ 这类允许直接操作内存地址的语言中,如果指针没有被正确初始化,或者指针所指向的内存已经被释放,那么这个指针就成为了野指针。使用野指针可能会导致程序崩溃、数据损坏或者其他一些不可预测的行为。 - 在什么情况下会产生野指针?
○ 在释放后没有置空指针: 使用 delete 或 free 释放了内存后,没有将指针设置为 nullptr,指针仍然指向已释放的内存地址。
○ 返回局部变量的指针 : 如果函数返回了指向其局部变量的指针,一旦函数返回,这些局部变量的生命周期结束,返回的指针成为野指针。
○ 越界访问:指针访问的内存超出了其合法的内存块边界。
○ 函数参数指针被释放。 - 如何避免野指针
○ 在释放内存后将指针置为 nullptr 。
○ 避免返回局部变量的指针。
○ 使用智能指针(如 std::unique_ptr 和 std::shared_ptr )。
○ 注意函数参数的生命周期,避免在函数内释放调用方传递的指针,或者通过引用传递指针。
C++内存分区
很多情况下,提到 C++ 程序的内存分区时,会简化为下面五个主要区域
● 栈(Stack): 用于存储局部变量和函数调用的上下文。栈的内存分配是自动的,由编译器管理。
● 堆(Heap): 用于动态内存分配。程序员可以使用 new、malloc 等操作符或函数从堆上分配内存,并使用 delete、free 释放内存。
● 全局/静态存储区(Global/Static Storage): 存储全局变量和静态变量,包括:
○ 数据段:存储初始化的全局变量和静态变量。
○ BSS 段:存储未初始化的全局变量和静态变量。
● 常量存储区(Constant Data): 存储程序中的常量数据,如字符串字面量。
● 代码段(Code Segment 或 Text Segment): 存储程序的可执行代码和函数的二进制指令。