在写c++程序中通常遇到程序崩溃,我们首先想到的是内存问题
如果代码量少看几遍就能看得出来,如果代码量多起来我们就得借助一些工具了比如gdb调试和valgrind中得memcheck来解决内存问题
我用的ubuntu,先安装valgrind
sudo apt update
sudo apt install valgrind
valgrind --version
常见的内存问题
- 悬空指针的读写
- 动态内存越界访问
- 内存泄漏
- double delete
- 不匹配的使用 new/delete 和malloc/free
- 访问野指针
悬空指针的读写
#inlude<iostream>
using namespace std;
int main()
{int* p=new int(10);delete p;int a=*p;cout<<a<<endl;
}
invalid read of size 4 显示我们代码7行在无效的读取4个字节的数据(int)
all heap blocks were free 显示堆内存没有内存泄漏
动态数组越界读写
#include<iostream>
using namespace std;
int main()
{int* a=new int[5];for(int i=0;i<=5;i++) a[i]=i;for(int i=0;i<=5;i++) cout<<a[i]<<endl;return 0;
}
特别的静态数组越界能通过gdb调试发现,但valgrind无能为力
内存泄漏
#include<iostream>
using namespace std;
int main()
{int *a=new int(10);return 0;
}
这里我们添加参数 --leak-check=full来看详细信息
出现两次
allocs
是因为程序中不仅有你显式分配的动态内存(new int(10)
),还可能有额外的内存分配来自程序运行时的环境或库的初始化其显示在第5行operate new出来的内存块丢失发生了内存泄漏
double delete
#include<iostream>
using namespace std;
int main()
{int* a=new int(10);delete a;delete a;return 0;
}
显示无效free 第5行申请内存,但是6,7行都释放了内存,如果是多线程情况下可能会使释放内存后,内存新数据的错误释放,造成数据安全问题,所以我们要避免double delete
不匹配的使用 new/delete 和malloc/free
#include<iostream>
using namespace std;
int main()
{int* a=new int(10);free(a);return 0;
}
会显示类型匹配问题
malloc和new的区别在于new在申请空间的同时会调用构造函数,并且new失败会抛出异常而malloc返回nullptr
delete 不仅会释放内存还会调用析构函数
当我们使用class时,就无法正常生成对象和析构对象
访问野指针
#include<iostream>
using namespace std;
int mian()
{int* p;int a=*p;
}
显示使用未初始化的指针
静态数组越界问题我们通过gdb调试可以调试出来,会显示栈溢出
总结
- 内存泄漏检测:能够跟踪动态内存分配,确保分配的内存在不再需要时被正确释放。
- 越界访问检测:帮助识别动态数组越界、空指针解引用等错误。
- 未初始化变量检测:检测使用未初始化变量的情况。
- 典型应用场景:当程序涉及大量的动态内存分配,或频繁出现无效内存访问、内存泄漏等问题时,用 Valgrind 非常有效。
借鉴于C++内存泄漏检查工具——Valgrind(--tool = memcheck) - unique_ptr - 博客园