linux-valgrind检测分析C/C++程序(三)
这章主要讲述valgrind的使用
官方 地址:https://valgrind.org/
检测内存泄漏
Windows平台下的内存检测方法
VLD(Visual Leak Detector)工具
CRT库
windows 性能分析 AQTIME
1:介绍
valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合。valgrind由内核(core)以及基于内核的调试工具组成。内核类似于一个框架(framework),它模拟了一个CPU环境,并提供服务给其它工具;而其它工具则类似于插件 (plug-in),利用内核提供的服务完成各种特定的调试分析任务。
Memcheck:内存错误检测器。 能够发现开发中绝大多数内存错误使用情况,比如:使用未初始化的内存,使用已经释放了的内存,内存访问越界等;
Cachegrind :缓存和分支预测分析器。 分析热点函数,函数调用流程等,它可以帮助您使程序运行得更快。模拟CPU中的一级缓存I1,Dl和二级缓存,能够精确地指出程序中cache的丢失和命中。如果需要,它还能够为我们提供cache丢失次数,内存引用次数,以及每行代码,每个函数,每个模块,整个程序产生的指令数。
Callgrind :调用图生成缓存分析器。 它与 Cachegrind 有一些重叠,但也收集了 Cachegrind 没有的一些信息。
Helgrind :线程错误检测器。Helgrind寻找内存中被多个线程访问,而又没有一贯加锁的区域,这些区域往往是线程之间失去同步的地方,而且会导致难以发掘的错误。 它可以帮助您使您的多线程程序更加正确。
DRD :线程错误检测器。 它与 Helgrind 类似,但使用不同的分析技术,因此可能会发现不同的问题。
Massif :堆分析器。能帮助我们减少内存的使用,在带有虚拟内存的现代系统中,它还能够加速我们程序的运行,减少程序停留在交换区中的几率。 它可以帮助您减少程序使用的内存。
DHAT :是一种不同类型的堆分析器。 它可以帮助您了解块寿命、块利用率和布局效率低下的问题。
BBV :实验性的 SimPoint 基本块向量生成器。 对于从事计算机体系结构研究和开发的人来说很有用。
2:安装
1>valgrind 安装
sudo apt-get install valgrind
2>KCacheGrind 安装(KCacheGrind是一个Linux下的性能分析工具,可以用来分析程序的运行时间和内存使用情况)
sudo apt-get update
sudo apt-get install kcachegrind
使用说明
Memcheck: 用于检测内存错误,如内存泄漏、非法内存访问等。
Callgrind: 用于收集程序运行时的函数调用信息,帮助进行性能分析。
Cachegrind: 它主要用来检查程序中缓存使用出现的问题。
Helgrind: 它主要用来检查多线程程序中出现的竞争问题。
Massif: 用于分析程序的内存使用情况,帮助优化内存分配。
valgrind不会自动的检查程序的每一行代码,只会检查运行到的代码分支。
编译代码时,建议增加-g -o0选项,不要使用-o1、-o2选项。这样错误信息才能定位到代码行
命令的语法格式
valgrind -q --tool=<tool_name> --log-file=<file_name> <other_options> ./<program_name>
-q: -quiet 安静地运行,只打印错误信息,如版本号。
–tool=<tool_name>: 要使用的工具名称,如:memcheck、callgrind,该选项未设置时,默认为memcheck。tool_name可以是
memcheck
callgrind
cachegrind
helgrind
massif
–log-file=<file_name>: 日志输出文件。
<other_options>: 针对tool_name的其他选项。
3:测试
测试代码
#include<iostream>
using namespace std;
#include<stdio.h>
#include<stdlib.h>
void no_leak_mem()
{
int *p[3] ={NULL,NULL,NULL};
p[0] = (int *)malloc(sizeof(int));
p[1] = (int *)malloc(sizeof(int) * 2);
p[2] = (int *)malloc(sizeof(int) * 3);
free(p[0]);
free(p[1]);
free(p[2]);
}
void has_leak_mem()
{
int *p[3] ={NULL,NULL,NULL};
p[0] = (int *)malloc(sizeof(int));
p[1] = (int *)malloc(sizeof(int) * 2);
p[2] = (int *)malloc(sizeof(int) * 3);
free(p[0]);
free(p[1]);
// free(p[2]);
}
//非法地址访问
void invalid_address_access()
{
int *p = NULL;
printf("val = %d\n", *p);
}
void corss_border_read_write()
{
int a = 0x10;
int *p = &a + 0x10;
//越界读 程序不崩溃,可能导致逻辑错误
printf("cross border address read %x\n", *p);
//越界写 程序错误
*p = 0x87654321;
//printf("cross border address write %x\n", *p);
}
int main(){
cout<<"test no_leak_mem"<<endl;
no_leak_mem();
cout<<"test has_leak_mem"<<endl;
has_leak_mem();
cout<<"test invalid_address_access"<<endl;
//invalid_address_access();
cout<<"test corss_border_read_write"<<endl;
corss_border_read_write();
cout<<"test finish"<<endl;
}
//g++ -g -o testleak ./testleak.cpp
//valgrind --leak-check=full ./testleak
运行结果
内存越界测试
#include<stdio.h>
#include<stdlib.h>
int main(){
int i;
int len = 8;
int *pt = (int*)malloc(len*sizeof(int));
int *p = pt;
for(i=0;i<len;i++)
{
p++;
}
*p = 9;
return 0;
}
性能分析
#include <unistd.h>
#include <stdlib.h>
#include <thread>
#include <iostream>
void thread_routine(unsigned long long n) {
while (true) {
const int array_size = 32;
char buf[array_size] = {0};
sprintf(buf, "%lu\n", n++);
printf(buf);
}
}
int main() {
std::thread t(thread_routine, 0);
t.detach();
sleep(10);
return 0;
}
//g++ -O0 -g -std=c++11 -lpthread testcallgrind.cpp -o test3
//valgrind --tool=callgrind --separate-threads=yes ./test3
//kcachegrind ./callgrind.out.20486
用kcachegrind ./callgrind.out.20486 查看
valgrind 其他的工具 后面有空再补上
4:如果觉得有用,麻烦点个赞,加个收藏