C++内存泄漏/内存越界的各种情况,以及预防与排查

您所在的位置:网站首页 怎么读内存 C++内存泄漏/内存越界的各种情况,以及预防与排查

C++内存泄漏/内存越界的各种情况,以及预防与排查

2024-07-11 20:34| 来源: 网络整理| 查看: 265

目录

一、内存泄漏

一、介绍

二、几种内存泄露的场景

三、预防与排查

1、valgrind

二、内存越界

一、介绍

二、几种内存越界的情况

三、预防与排查

 

一、内存泄漏 一、介绍 内存泄漏,是指在程序代码中动态申请的、堆上的内存 由于某种原因、在使用后没有被释放,进而造成内存的浪费。 少部分的内存泄漏不会影响程序的正常运行,不过如果是持续的内存泄漏会耗光系统内存,最终会导致程序卡死甚至系统崩溃。为了避免系统崩溃,在无法申请到内存的时候,要果断调用exit()函数主动杀死进程,而不是试图挽救这个进程。 二、几种内存泄露的场景

1、malloc/new申请的内存没有主动释放

    void test1()   {   char* str = new char[100];   /*delete[] str; 这里忘记delete了 */   }    

2、new与free混用,malloc与delete混用

    class Base   {   public:   int* values;   Base() { values = new int[100]; }   ~Base() { delete[] values; }   };       void test2()   {   Base* pBase = new Base;       free(pBase);   /* 错误,这样只会释放pBase指向的内存,却不会调用Base的析构函数   会导致Base中的values指向的内存无法被释放 */       delete pBase; /* 正确 */   }    

3、使用new开辟数组时,delete忘记加[]

    void test3()   {   int* vects = new int[100];       delete vects; // 这种写法是错误的   delete[] vects; // 这种写法是正确的   }    

4、基类的析构函数没有定义为虚函数

    class A   {   public:   A() {}   ~A() {}   };       class B : public A   {   public:   B() { num = new int[100]; }   ~B() { delete[] num; }   private:   int* num;   };       void main() {   A* pa = new B();       delete pa;   /* 这样只会调用A类的析构函数,而B类中的num就得不到释放   正确的是应该把A的析构类声明为虚函数 */   }     三、预防与排查 1、valgrind 应用环境:Linux 编程语言:C/C++ 使用方法:  编译时加上-g选项,如 gcc -g filename.c  -o filename,使用如下命令检测内存使用情况: 结果输出:#valgrind --tool=memcheck --leak-check=yes --show-reachable=yes ./filename,就会看到内存使用报告 设计思路:根据软件的内存操作维护一个有效地址空间表和无效地址空间表(进程的地址空间) 优缺点:能够检测: 使用未初始化的内存 (Use of uninitialised memory) 使用已经释放了的内存 (Reading/writing memory after it has been free’d) 使用超过 malloc分配的内存空间(Reading/writing off the end of malloc’d blocks) 对堆栈的非法访问 (Reading/writing inappropriate areas on the stack) 申请的空间是否有释放 (Memory leaks – where pointers to malloc’d blocks are lost forever) malloc/free/new/delete申请和释放内存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete []) src和dst的重叠(Overlapping src and dst pointers in memcpy() and related functions) 重复free 如何获取:http://valgrind.org/

2、使用智能指针

    void test4()   {   // 以下两种写法效果相同   shared_ptr p1 = shared_ptr(new int(234));   shared_ptr p2 = make_shared(234);       // 还有其他指针指针   weak_ptr p3 = weak_ptr(p1);   unique_ptr p4 = unique_ptr(new int(234));   auto_ptr p5 = auto_ptr(new int(234));   }     二、内存越界 一、介绍 内存越界是软件系统主要错误之一,其后果往往不可预料且非常严重。更麻烦的是,它出现的时机是随机的,表现出来的症状是随机的,而且造成的后果也是随机的,这会使程序员很难找出这些 Bug 的现象和本质之间的联系,从而给 Bug 的定位带来极大的困难。一般情况下,内存越界访问可分如下两种: 读越界,即读了不属于自己的数据。如果所读的内存地址是无效的,程序立刻崩溃;如果所读内存地址是有效的,在读的时候不会马上出现问题,但由于读到的数据是随机的,因此它会造成不可预料的后果。 写越界,又称为缓冲区溢出,所写入的数据对别的程序来说是随机的,它也会造成不可预料的后果。 二、几种内存越界的情况 定义指针的时候未初始化,所以指针指向的时一块随机值,用户并不一定有访问权限。 分配到的内存比实际上使用的内存要小。 使用下标访问数组时,下标错误。 内存已经被释放了,但仍指针来使用这块内存。 三、预防与排查 定义指针变量的时候,如果暂时不初始化,可以先让它指向 nullptr。 分配内存时,用户要检查内存是否分配成功。 使用下标访问数组的时候,要检查是否越界。 内存被释放之后,指向这块内存的指针也要赋值为 nullptr。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3