内存泄漏检测之Valgrind的使用
工具介绍
Valgrind 是 Linux 下强大的内存调试和性能分析工具,其 Memcheck 工具可以有效检测内存泄漏。
Linux下的安装
Ubuntu下
sudo apt update
sudo apt install valgrind
CentOS下
sudo yum install valgrind
Valgrind的使用
测试代码
#include<iostream>
#include <vector>
#include<memory>
using namespace std;class base{
private:int *a;
public:base(int a): a(new int(a)){cout<<"base 构造函数调用!"<<endl;}~base(){/*delete a;*/}
};class ptr_B;class ptr_A{
private :public:shared_ptr<ptr_B> b;ptr_A(){cout<<"ptr_A构造函数调用"<<endl;}
};class ptr_B{
private:public:shared_ptr<ptr_A> a;ptr_B(){cout<<"ptr_B构造函数调用"<<endl;}
};int main(){//常规动态分配内存忘了deleteint *testA=new int(0);//类的构造忘了析构base b=base(1);//shared_ptr的循环引用shared_ptr<ptr_A> testPtr_A= make_shared<ptr_A>();shared_ptr<ptr_B> testPtr_B= make_shared<ptr_B>();testPtr_A->b=testPtr_B; testPtr_B->a=testPtr_A;cout<<"代码运行结束!Good Luck!"<<endl;return 0;
}
编译程序时添加调试信息
g++ -g -o0 test.cpp -o test
使用 Valgrind 运行程序
valgrind --leak-check=full --show-leak-kinds=all ./test
-
--leak-check=full
:全面检查内存泄漏 -
--show-leak-kinds=all
:显示所有泄漏类型(包括可能的和确定的)
关键选项说明
--leak-check=full
:详细分析内存泄漏,显示泄漏的内存块位置
--show-leak-kinds=all : 显示所有泄漏类型: - `definite`:确定的泄漏
- `possible`:可能的泄漏
- `indirect`:间接泄漏
- `still-reachable`:未释放但仍可访问
--track-origins=yes
:跟踪未初始化变量的来源(定位使用未初始化值的错误)
--log-file=valgrind.log
:将输出结果保存到文件
--num-callers=20
:显示堆栈回溯的深度(默认 12 层)
--suppressions=file.supp
:忽略特定类型的错误(如第三方库的误报)
valgrind --tool=massif ./test :按照时间来分析堆上的内容数据变化,每隔一段时间拍快照
结果分析
分析内容在“ # ”后面
valgrind运行结果:
==9968== Memcheck, a memory error detector
==9968== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==9968== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==9968== Command: ./test
==9968==
base 构造函数调用!
ptr_A构造函数调用
ptr_B构造函数调用
代码运行结束!Good Luck!
==9968==
==9968== HEAP SUMMARY:
==9968== in use at exit: 72 bytes in 4 blocks #退出时仍然后4个内存处于使用状态,共占用72字节的堆内存!也就是内存泄漏
==9968== total heap usage: 6 allocs, 2 frees, 73,800 bytes allocated #整个运行过程中,堆进行了6次的分配操作,2次释放操作
==9968==
==9968== 4 bytes in 1 blocks are definitely lost in loss record 1 of 4 #第一个泄露的地方
==9968== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==9968== by 0x1092CD: main (test.cpp:39) #第39行的new 操作没有delete
==9968==
==9968== 4 bytes in 1 blocks are definitely lost in loss record 2 of 4 #第二个泄漏的地方
==9968== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==9968== by 0x10961A: base::base(int) (test.cpp:10)
==9968== by 0x1092E8: main (test.cpp:43) #main函数43行中base的构造函数,中间的new操作没有delete
==9968==
==9968== 32 bytes in 1 blocks are indirectly lost in loss record 3 of 4 #第三个泄漏的地方 表示存在间接内存泄漏,总结来就是循环引用
==9968== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==9968== by 0x10AAE9: __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<ptr_B, std::allocator<ptr_B>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) (new_allocator.h:114)
==9968== by 0x10A882: std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<ptr_B, std::allocator<ptr_B>, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::allocator<std::_Sp_counted_ptr_inplace<ptr_B, std::allocator<ptr_B>, (__gnu_cxx::_Lock_policy)2> >&, unsigned long) (alloc_traits.h:443)
==9968== by 0x10A4A7: std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<ptr_B, std::allocator<ptr_B>, (__gnu_cxx::_Lock_policy)2> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<ptr_B, std::allocator<ptr_B>, (__gnu_cxx::_Lock_policy)2> > >(std::allocator<std::_Sp_counted_ptr_inplace<ptr_B, std::allocator<ptr_B>, (__gnu_cxx::_Lock_policy)2> >&) (allocated_ptr.h:97)
==9968== by 0x10A0AD: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<ptr_B, std::allocator<ptr_B>>(ptr_B*&, std::_Sp_alloc_shared_tag<std::allocator<ptr_B> >) (shared_ptr_base.h:677)
==9968== by 0x109ECF: std::__shared_ptr<ptr_B, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<ptr_B>>(std::_Sp_alloc_shared_tag<std::allocator<ptr_B> >) (shared_ptr_base.h:1344)
==9968== by 0x109DC4: std::shared_ptr<ptr_B>::shared_ptr<std::allocator<ptr_B>>(std::_Sp_alloc_shared_tag<std::allocator<ptr_B> >) (shared_ptr.h:359)
==9968== by 0x109C7D: std::shared_ptr<ptr_B> std::allocate_shared<ptr_B, std::allocator<ptr_B>>(std::allocator<ptr_B> const&) (shared_ptr.h:702)
==9968== by 0x1099DB: std::shared_ptr<ptr_B> std::make_shared<ptr_B>() (shared_ptr.h:718)
==9968== by 0x109300: main (test.cpp:47)
==9968==
==9968== 64 (32 direct, 32 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4 #第四个地方
==9968== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==9968== by 0x10A9CD: __gnu_cxx::new_allocator<std::_Sp_counted_ptr_inplace<ptr_A, std::allocator<ptr_A>, (__gnu_cxx::_Lock_policy)2> >::allocate(unsigned long, void const*) (new_allocator.h:114)
==9968== by 0x10A6FC: std::allocator_traits<std::allocator<std::_Sp_counted_ptr_inplace<ptr_A, std::allocator<ptr_A>, (__gnu_cxx::_Lock_policy)2> > >::allocate(std::allocator<std::_Sp_counted_ptr_inplace<ptr_A, std::allocator<ptr_A>, (__gnu_cxx::_Lock_policy)2> >&, unsigned long) (alloc_traits.h:443)
==9968== by 0x10A235: std::__allocated_ptr<std::allocator<std::_Sp_counted_ptr_inplace<ptr_A, std::allocator<ptr_A>, (__gnu_cxx::_Lock_policy)2> > > std::__allocate_guarded<std::allocator<std::_Sp_counted_ptr_inplace<ptr_A, std::allocator<ptr_A>, (__gnu_cxx::_Lock_policy)2> > >(std::allocator<std::_Sp_counted_ptr_inplace<ptr_A, std::allocator<ptr_A>, (__gnu_cxx::_Lock_policy)2> >&) (allocated_ptr.h:97)
==9968== by 0x109F3B: std::__shared_count<(__gnu_cxx::_Lock_policy)2>::__shared_count<ptr_A, std::allocator<ptr_A>>(ptr_A*&, std::_Sp_alloc_shared_tag<std::allocator<ptr_A> >) (shared_ptr_base.h:677)
==9968== by 0x109E7B: std::__shared_ptr<ptr_A, (__gnu_cxx::_Lock_policy)2>::__shared_ptr<std::allocator<ptr_A>>(std::_Sp_alloc_shared_tag<std::allocator<ptr_A> >) (shared_ptr_base.h:1344)
==9968== by 0x109D7A: std::shared_ptr<ptr_A>::shared_ptr<std::allocator<ptr_A>>(std::_Sp_alloc_shared_tag<std::allocator<ptr_A> >) (shared_ptr.h:359)
==9968== by 0x109C11: std::shared_ptr<ptr_A> std::allocate_shared<ptr_A, std::allocator<ptr_A>>(std::allocator<ptr_A> const&) (shared_ptr.h:702)
==9968== by 0x109951: std::shared_ptr<ptr_A> std::make_shared<ptr_A>() (shared_ptr.h:718)
==9968== by 0x1092F4: main (test.cpp:46)
==9968==
==9968== LEAK SUMMARY:
==9968== definitely lost: 40 bytes in 3 blocks #确定的内存泄漏
==9968== indirectly lost: 32 bytes in 1 blocks #不确定的间接内存泄漏
==9968== possibly lost: 0 bytes in 0 blocks
==9968== still reachable: 0 bytes in 0 blocks
==9968== suppressed: 0 bytes in 0 blocks
==9968==
==9968== For lists of detected and suppressed errors, rerun with: -s
==9968== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)