C++ 复制控制 Copy Control 示例, 及内存泄漏检测工具 Valgrind 的简单使用
主页: http://valgrind.org/
文档下载:http://valgrind.org/docs/download_docs.html
简单使用: http://cs.ecs.baylor.edu/~donahoo/tools/valgrind/
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./test
Valgrind is an instrumentation framework for building dynamic analysis tools. There are Valgrind tools that can automatically detect many memory management and threading bugs, and profile your programs in detail. You can also use Valgrind to build new tools.
The Valgrind distribution currently includes six production-quality tools: a memory error detector, two thread error detectors, a cache and branch-prediction profiler, a call-graph generating cache and branch-prediction profiler, and a heap profiler. It also includes three experimental tools: a heap/stack/global array overrun detector, a second heap profiler that examines how heap blocks are used, and a SimPoint basic block vector generator. It runs on the following platforms: X86/Linux, AMD64/Linux, ARM/Linux, PPC32/Linux, PPC64/Linux, S390X/Linux, MIPS/Linux, ARM/Android (2.3.x and later), X86/Android (4.0 and later), X86/Darwin and AMD64/Darwin (Mac OS X 10.6 and 10.7, with limited support for 10.8).
当源代码使用 -g 选项编时,valgrind 可以定位出现内存泄漏的行号, 无-g选项也是可以的。
如: g++ -g HasPtr.cxx
/* * HasPtr.cxx * */ #include <iostream> using namespace std; class HasPtr{ public: //默认构造函数 HasPtr(){ cout<<"HasPtr默认构造函数被调用"<<hex<<this<<dec<<endl; //pval = new int(0); //#1 pval = NULL; val = 0; } //正常构造函数 HasPtr(const int * rhs,int ival = 0){ cout<<"HasPtr构造函数被调用,this@"<<hex<<this<<dec<<endl; pval = new int(*rhs); val = ival; } //复制构造函数 HasPtr(const HasPtr & rhs){ cout<<"HasPtr复制构造函数被调用,this@"<<hex<<this<<dec<<endl; pval = new int(*rhs.pval); val = rhs.val; } //赋值操作符 HasPtr & operator = (const HasPtr & rhs){ cout<<"HasPtr operator = 函数被调用,this@"<<hex<<this<<dec<<endl; //*pval = *rhs.pval; //#1处,在默认构造中也有分配指针所指对象,则直接赋值 /***************************************************/ delete pval; //删除NULL指针是安全的,注释掉这行,可以查看到内存泄漏 /***************************************************/ pval = new int(*rhs.pval); val = rhs.val; return *this; } //构造函数 ~HasPtr(){ delete pval; cout<<"HasPtr析造函数被调用,this@"<<hex<<this<<dec<<endl; } void to_str(){ cout<<"HasPtr.to_str() called:val="<<val <<",*pval="<<*pval <<",pval="<<hex<<pval<< ",this@"<<hex<<this<<dec<<endl<<endl; } //private: int val,*pval; }; int main(int argc, char **argv) { int i =110; HasPtr p1(&i,2); p1.to_str(); //HasPtr p2(&i,2); //常规构造函数 //HasPtr p2(p1); //复制构造函数 //HasPtr p2 = p1; //复制构造函数 HasPtr p2; //默认构造 p2 = p1; //赋值操作符 p2.to_str(); p2.val *=2; *p2.pval *=2; cout<<"########## after change ##########"<<endl; p1.to_str(); p2.to_str(); p1 = p2; cout<<"######## p1 = p2 ############"<<endl; p1.to_str(); p2.to_str(); return 0; }
检测结如下:
spark@spark-vbox:~/workspace/Cpp$ valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./a.out ==5837== Memcheck, a memory error detector ==5837== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al. ==5837== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info ==5837== Command: ./a.out ==5837== HasPtr构造函数被调用,this@0xbee6204c HasPtr.to_str() called:val=2,*pval=110,pval=0x4323028,this@0xbee6204c HasPtr默认构造函数被调用0xbee62054 HasPtr operator = 函数被调用,this@0xbee62054 HasPtr.to_str() called:val=2,*pval=110,pval=0x4323060,this@0xbee62054 ########## after change ########## HasPtr.to_str() called:val=2,*pval=110,pval=0x4323028,this@0xbee6204c HasPtr.to_str() called:val=4,*pval=220,pval=0x4323060,this@0xbee62054 HasPtr operator = 函数被调用,this@0xbee6204c ######## p1 = p2 ############ HasPtr.to_str() called:val=4,*pval=220,pval=0x4323098,this@0xbee6204c HasPtr.to_str() called:val=4,*pval=220,pval=0x4323060,this@0xbee62054 HasPtr析造函数被调用,this@0xbee62054 HasPtr析造函数被调用,this@0xbee6204c ==5837== ==5837== FILE DESCRIPTORS: 3 open at exit. ==5837== Open file descriptor 2: /dev/pts/2 ==5837== <inherited from parent> ==5837== ==5837== Open file descriptor 1: /dev/pts/2 ==5837== <inherited from parent> ==5837== ==5837== Open file descriptor 0: /dev/pts/2 ==5837== <inherited from parent> ==5837== ==5837== ==5837== HEAP SUMMARY: ==5837== in use at exit: 4 bytes in 1 blocks ==5837== total heap usage: 3 allocs, 2 frees, 12 bytes allocated ==5837== ==5837== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1 ==5837== at 0x402B9B4: operator new(unsigned int) (in /usr/lib/valgrind/vgpreload_memcheck-x86-linux.so) ==5837== by 0x8048B86: HasPtr::HasPtr(int const*, int) (HasPtr.cxx:20) ==5837== by 0x8048821: main (HasPtr.cxx:58) ==5837== ==5837== LEAK SUMMARY: ==5837== definitely lost: 4 bytes in 1 blocks ==5837== indirectly lost: 0 bytes in 0 blocks ==5837== possibly lost: 0 bytes in 0 blocks ==5837== still reachable: 0 bytes in 0 blocks ==5837== suppressed: 0 bytes in 0 blocks ==5837== ==5837== For counts of detected and suppressed errors, rerun with: -v ==5837== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
它可以检测出在哪一行分配的内存没有被释放,不能给出合适的应该释放的位置,这确实难办到,分析时要注意。