本文主要是介绍C++ 内存泄漏检测工具——Valgrind(Linux系统),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
C++ 内存泄漏检测工具——Valgrind(Linux系统)
参考来源:valgrind基本功能介绍、基础使用方法说明
文章目录
- C++ 内存泄漏检测工具——Valgrind(Linux系统)
- Valgrind
- 下载和安装
- Valgrind 使用选项
- Memcheck工具
- 例子
Valgrind
Valgrind 是Linux系统下,开放源代码的仿真调试工具的集合。我们可以利用该工具对基于C、C++语言写的项目进行内存泄漏等多个方面进行检测。
下载和安装
https://www.valgrind.org/downloads/
下载好后,到下载目录下,打开终端, 输入以下命令:
# 解压
tar -jxvf valgrind-3.21.0.tar.bz2
# 进入解压目录
cd valgrind-3.21.0
# 执行安装配置命令
./configure --prefix=/usr/local/valgrind-3.21.0
# 编译
make
# 安装
make install
# 建立软链接
ln -s /usr/local/valgrind-3.21.0/bin/valgrind /usr/bin/valgrind
好像也可以用命令安装linux valgrind 安装和使用
sudo apt-get install valgrind
Valgrind 使用选项
(1)Memcheck。这是valgrind应用最广泛的工具,一个重量级的内存检查器,能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等。这也是本文将重点介绍的部分。
(2)Callgrind。它主要用来检查程序中函数调用过程中出现的问题。
(3)Cachegrind。它主要用来检查程序中缓存使用出现的问题。
(4)Helgrind。它主要用来检查多线程程序中出现的竞争问题。
(5)Massif。它主要用来检查程序中堆栈使用中出现的问题。
1)适用于所有Valgrind工具
–tool=< name > 最常用的选项。运行 valgrind中名为toolname的工具。默认memcheck,还包括cachegrind callgrind helgrind drd massif dhat lackey none exp-bbv
-h --help 显示帮助信息。
–version 显示valgrind内核的版本,每个工具都有各自的版本。
-q --quiet 安静地运行,只打印错误信息。
-v --verbose 更详细的信息, 增加错误数统计。
–trace-children=no|yes 跟踪子线程? [no]
–track-fds=no|yes 跟踪打开的文件描述?[no]
–time-stamp=no|yes 增加时间戳到LOG信息? [no]
–log-fd=< number > 输出LOG到描述符文件 [2=stderr]
–log-file=< file > 将输出的信息写入到filename.PID的文件里,PID是运行程序的进行ID
–log-file-exactly=< file > 输出LOG信息到 file
–log-file-qualifier=< VAR > 取得环境变量的值来做为输出信息的文件名。 [none]
–log-socket=ipaddr:port 输出LOG到socket ,ipaddr:port
(2)LOG信息输出
–xml=yes 将信息以xml格式输出,只有memcheck可用
–num-callers=< number > show < numbe r> callers in stack traces [12]
–error-limit=no|yes 如果太多错误,则停止显示新错误? [yes]
–error-exitcode=< number > 如果发现错误则返回错误代码 [0=disable]
–db-attach=no|yes 当出现错误,valgrind会自动启动调试器gdb。[no]
–db-command=< command > 启动调试器的命令行选项[gdb -nw %f %p]
(3)适用于Memcheck工具的相关选项:
–leak-check=no|summary|full 要求对leak给出详细信息? [summary]
–leak-resolution=low|med|high how much bt merging in leak check [low]
–show-reachable=no|yes show reachable blocks in leak check? [no]
更详细的使用信息详见帮助文件、man手册或官网:http://valgrind.org/docs/manual/manual-core.html
对于内存泄漏方面:
valgrind --tool=memcheck --leak-check=full --log-file=log.txt ./main# --tool=memcheck 针对内存检测是固定使用memcheck的
# --leak-check=full 将给出内存泄漏的完整信息
# --leak-check=yes 将给出内存泄漏的信息,但是可能不太好定位
# --leak-check=summary 这个效果跟--leak-check=yes是差不多的
# --log-file=log.txt 则会将内存检测的信息写入到log.txt文件下,log.txt文件在终端当前目录下
# ./main 是linux可执行的程序,这个可执行程序名为main
Memcheck工具
Memcheck主要检测以下错误:
(1) 使用未初始化的内存(Use of uninitialised memory)
(2) 使用已经释放了的内存(Reading/writing memory after it has been free’d)
(3) 使用超过malloc分配的内存空间(Reading/writing off the end of malloc’d blocks)
(4) 对堆栈的非法访问(Reading/writing inappropriate areas on the stack)
(5) 申请的空间是否有释放(Memory leaks – where pointers to malloc’d blocks are lost forever)
(6) malloc/free/new/delete申请和释放内存的匹配(Mismatched use of malloc/new/new [] vs free/delete/delete [])
(7) src和dst的重叠(Overlapping src and dst pointers in memcpy() and related functions)
前六种是比较常见的问题,内存泄漏主要是有(4)(5)引起的,由于程序中申请了空间,但是没有在程序结束或是在函数结束时正确的释放,导致这段空间被无法在后面的程序中继续使用。对于数据量较大的程序,这是很危险的,由于内存占用问题,尽管函数或程序可能执行完毕,但是未被释放,但是内存仍被占用,这些空间无法后续使用或被其他程序使用,可能会导致计算机运行变慢,也可能导致后续程序无法正常运行。
例子
本文编译了一个名为PathPlanningFramework的程序,在程序中有一段代码是对矩阵作卷积的,为了测试是否存在内存泄漏的问题,使用如下命令。
valgrind --leak-check=full --log-file=output.txt ./PathPlanngFramework
到当面目录下查看输出log-file。
==51396== Memcheck, a memory error detector
==51396== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==51396== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==51396== Command: ./PathPlanningFramework
==51396== Parent PID: 30810
==51396==
==51396==
==51396== HEAP SUMMARY:
==51396== in use at exit: 40,804 bytes in 1 blocks
==51396== total heap usage: 1,239 allocs, 1,238 frees, 688,012 bytes allocated
==51396==
==51396== 40,804 bytes in 1 blocks are definitely lost in loss record 1 of 1
==51396== at 0x48487EF: malloc (vg_replace_malloc.c:442)
==51396== by 0x1155C3: void OpMatrix::conv<float>(float*, float*, int, int, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<float, std::allocator<float> >&, int&, int&, bool, bool) (in /home/sunx/WorkSpace/Project/C++Projects/PathPlanningFramework/cmake-build-debug/PathPlanningFramework)
==51396== by 0x116304: void OpMatrix::Conv<int, int, double>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&) (in /home/sunx/WorkSpace/Project/C++Projects/PathPlanningFramework/cmake-build-debug/PathPlanningFramework)
==51396== by 0x10F7D0: main (in /home/sunx/WorkSpace/Project/C++Projects/PathPlanningFramework/cmake-build-debug/PathPlanningFramework)
==51396==
==51396== LEAK SUMMARY:
==51396== definitely lost: 40,804 bytes in 1 blocks
==51396== indirectly lost: 0 bytes in 0 blocks
==51396== possibly lost: 0 bytes in 0 blocks
==51396== still reachable: 0 bytes in 0 blocks
==51396== suppressed: 0 bytes in 0 blocks
==51396==
==51396== For lists of detected and suppressed errors, rerun with: -s
==51396== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
可以看到存在40804bytes的内存泄漏。具体的泄漏位置是在OpMatrix::conv<float>(float*, float*, int, int, int, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<float, std::allocator<float> >&, int&, int&, bool, bool)
,由这个函数引起的。这个函数被void OpMatrix::Conv<int, int, double>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&)
,而Conv
被main
调用,最终导致内存泄漏。
那么就去检查conv
函数,看看是哪一部分的内存申请了,但是没有释放。
template <typename _Tp>void conv(_Tp* matrix, _Tp* corner, int matrix_w, int matrix_h, int corner_length, std::string conv_type, std::vector<_Tp> & result, int & result_h, int & result_w, bool show, bool is_rot) {result_w = matrix_w - corner_length + 1;result_h = matrix_h - corner_length + 1;// 卷积核逆时针旋转180度if (is_rot) {corner = rot90(corner, corner_length, 2, false);}int conv_key = convtype_str_id.at(conv_type);switch (conv_key){case ID_valid:// 卷积结果的尺寸((matrix_h - corner_length + 1),(matrix_w - corner_length + 1))result_w = matrix_w - corner_length + 1;result_h = matrix_h - corner_length + 1;result.resize(result_w*result_h);// 申请矩阵卷积的运算结果的内存空间
// result = (_Tp*)malloc(sizeof(_Tp)*result_w*result_h);for (int i = 0; i < result_h; i++) {for (int j = 0; j < result_w; j++) {result[i*result_w + j] = 0;for (int z = 0; z < corner_length; z++) {for (int q = 0; q < corner_length; q++) {result[i*result_w + j] += matrix[(i + z)*matrix_w + j + q] * corner[z*corner_length + q];}}}}break;case ID_full://result = (_Tp*)malloc(sizeof(_Tp)*(matrix_w + corner_length - 1)*(matrix_h + corner_length - 1));// 如果corner的边长为奇数,则用corner的中心点对应matrix的扫描到的点进行卷积运算if (corner_length % 2 == 0) {std::cout << "same型卷积要求卷积核尺寸为奇数" << std::endl;return;}else {// 创建新的matrix_new,用0填充原始matrix_Tp* matrix_new = padMatrix(matrix, matrix_w, matrix_h, matrix_w + 2 * corner_length - 2, matrix_h + 2 * corner_length - 2, false);// 对matrix_new进行full卷积,变相实现same型卷积conv(matrix_new, corner, matrix_w + 2 * corner_length - 2, matrix_h + 2 * corner_length - 2, corner_length, "valid", result, result_h, result_w, show, false);// 释放新申请的空间// free(matrix_new);return;}break;case ID_same://result = (_Tp*)malloc(sizeof(_Tp)*matrix_w*matrix_h);// 如果corner的边长为奇数,则用corner的中心点对应matrix的扫描到的点进行卷积运算if (corner_length % 2 == 0) {std::cout << "same型卷积要求卷积核尺寸为奇数" << std::endl;return;}else {// 创建新的matrix_new,用0填充原始matrix_Tp* matrix_new = padMatrix(matrix, matrix_w, matrix_h, matrix_w + corner_length - 1, matrix_h + corner_length - 1, false);// 对matrix_new进行full卷积,变相实现same型卷积//free(result);conv(matrix_new, corner, matrix_w + corner_length - 1, matrix_h + corner_length - 1, corner_length, "valid", result, result_h, result_w, show, false);// 释放原始matrix// free(matrix_new);return;}break;default:throw "请输入正确的卷积操作类型!";return;}// 打印计算结果
// if(saveR){
// Array2Vector<_Tp1, _Tp>(save, result, result_h, result_w);
// }if (show) {showMatrix(result, result_w, result_h);}}
仔细查看,发现是matrix_new
这段空间申请了,但是没有及时释放,所以在后面合适的位置,使用free(matrix_new)
释放空间即可。
==51936== Memcheck, a memory error detector
==51936== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==51936== Using Valgrind-3.22.0 and LibVEX; rerun with -h for copyright info
==51936== Command: ./PathPlanningFramework
==51936== Parent PID: 30810
==51936==
==51936==
==51936== HEAP SUMMARY:
==51936== in use at exit: 0 bytes in 0 blocks
==51936== total heap usage: 1,239 allocs, 1,239 frees, 688,012 bytes allocated
==51936==
==51936== All heap blocks were freed -- no leaks are possible
==51936==
==51936== For lists of detected and suppressed errors, rerun with: -s
==51936== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
修改后再次进行检测,可以看到没有内存泄漏问题。
这篇关于C++ 内存泄漏检测工具——Valgrind(Linux系统)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!