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)山峦, 它主要用以查验程序里堆栈运用当中所呈现的问题。
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 跟踪子线程?
–track-fds=no|yes 跟踪打开的文件描述?
, 是否要把时间戳增添至日志信息, –time - stamp标记处可选择no或者yes?
将LOG输出到描述符文件, 条件是 –log-fd 等于 < number >。
将输出的信息写入到filename.PID的文件里, 其中, PID是运行程序的进程ID, 而–log - file=< file >用于此操作。
将LOG信息输出到, 那个名为file的文件之中, 是通过–log - file - exactly = < file >来达成的。
采用获取环境变量的值的方式, 将其设定为输出信息的文件名, 具体通过 –log - file - qualifier =< VAR > 来达成。
将–log - socket等于ipaddr:port, 把LOG输出到socket, 此socket的地址为ipaddr:port。
(2)LOG信息输出
“–xml=yes”, 它能够以xml格式输出信息, 并且只有在memcheck可用的情况下才行。
将“–编号呼叫者=〈数字〉”,用以在堆栈跟踪中显示〈数字〉个数的呼叫者 , 有这样的作用。
问: –error-limit 的取值是 no 或者 yes, 要是出现过多错误, 那么会停止显示新错误吗?
若出现了发现错误这种情况, 那么会返回错误代码, 此错误代码为小于某个数字的数值, 该数值由“–error-exitcode=< number >”所表示。
0=disable

当出现错误时, –db-attach=no|yes这种情况, valgrind会自动启动调试器gdb。
–db-command参数所对应的, 是用于启动调试器的命令行选项, 该选项的值为< command >。
gdb -nw %f %p
(3)适用于Memcheck工具的相关选项:
设置为–leak-check=no|summary|full, 是要求针对leak给出详尽的信息吗?
就泄漏分辨率而言, 其取值为低、中级或者高级, 那么在泄漏检查以及数据合并过程中究竟达到何种程度, 会涉及到多少数据合并操作, 再者数据合并在泄漏检查里又占据怎样的情况。
在泄漏检查中, 是否显示可到达的块, 有两种选项, 分别是“否”或者“是”?
更详细的使用信息详见帮助文件、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) 运用尚未初始化的内存, 使用未初始化的内存, 使用未经初始化的内存, 使用未初始化过的内存, 使用未初始化的那块内存, 使用未初始化的内存这种情况。
(2) 在内存已被释放之后去进行对该内存的读取或写入操作, (Reading/writing memory after it has been free’d)。
(3) 进行超出通过malloc所分配的内存空间的使用操作, (即对通过malloc分配的内存块末尾进行读取/写入)。
(4) (在堆栈上)对于不恰当区域的读取或者写入这样的行为, 是对堆栈的非法访问。
(5) 申请的那个空间, 会不会有得到释放的情况呢, (内存泄漏——指向通过malloc分配的块的指针会永远丢失)
(6) 使用malloc来申请内存, 但是却用free以外的方式去释放它, 或者使用new来申请内存, 却用delete以外的方式去释放它, 这种内存申请与释放的方式存在着不匹配的情况, 也就是所谓的malloc/new/new与free/delete/delete的不匹配使用。
(7) src与dst的重叠, 在memcpy()之中以及相关函数内部针对src指针和dst指针的重叠 , 标点符号用逗号隔开。也要有的, 不然不算符合要求。
开头的前头六种是较为平常的常见问题, 内存泄漏主要是由(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*, int, int, int, std::__cxx11::basic_string, std::allocator >, std::vector >&, int&, int&, bool, bool) (in /home/sunx/WorkSpace/Project/C++Projects/PathPlanningFramework/cmake-build-debug/PathPlanningFramework)
==51396== by 0x116304: void OpMatrix::Conv(std::vector >, std::allocator > > >, std::vector >, std::allocator > > >, std::vector >, std::allocator > > >&) (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)
能够看到存在着40804字节的内存泄漏状况, 具体有内存泄漏的位置是处于OpMatrix::conv(float*, float*, int, int, int, std::__cxx11::basic_string, std::allocator >, std::vector >.& 这一函数之中, 是被这个函数所引发导致的。这个函数, 被void OpMatrix::Conv(std::vector >,std::allocator > > >,std::vector >,std::allocator > > >,std::vector >,std::allocator > > >&)这样的操作, 而Conv, 是被main调用的, 最终, 导致了内存泄漏。
那么, 前往检查conv函数, 去瞧瞧是哪一部分之内存获申请了, 然而却未曾被释放掉。
template
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)
修改后再次进行检测,可以看到没有内存泄漏问题。