程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Linux下c++程序內存洩漏檢測代碼范例

Linux下c++程序內存洩漏檢測代碼范例

編輯:C++入門知識

Linux下c++程序內存洩漏檢測代碼范例


Linux下對於程序內存洩漏檢測的方法很多,最常用的的莫過於使用valgrind工具。但是valgrind相當於讓程序在虛擬機中運行,會帶 來較大的系統資源開銷,還會對程序的運行效率產生較大影響,對於那種資源占用大的程序,如果需要長時間運行才能暴露的洩漏問題,它就顯得不太好用。

linux下的c++程序中自己實現一個輕量級的洩漏檢測代碼其實是比較方便的,下面我就給出一個簡單的范例,並作簡單的說明。當然,我們還是應該提倡使用共享指針,用共享指針自動管理內存可以避免內存洩漏這樣的不必要的麻煩。

 Linux下c++程序內存洩漏檢測代碼范例

基本原理:
  • 利用glibc提供的__malloc_hook, __free_hook系列函數對內存分配是否做監控;詳見glibc的官方文檔)
  • 利用backtrace函數獲取函數調用棧,並記錄;
  • 利用backtrace_symbols對調用棧對應的函數做解析;

進一步處理:

  •  使用abi::__cxa_demangle把函數名解析為源代碼風格;
  •  使用addr2line解析出函數調用棧對應的代碼行;
  •  對於動態庫.so)中的地址解析,需要先在/proc/<pid>/maps文件中找到動態庫映射的基地址,才能做解析。

注意:

編譯連接參數中使用-g -rdynamic

以上每步具體實現的代碼可能都沒有達到最優,甚至可能是笨辦法,如果有更好的實現方案請直接替換,也歡迎賜教。

示例代碼:

leakmom.cpp

  1. /* Prototypes for __malloc_hook, __free_hook */ 
  2. #include <malloc.h> 
  3. #include <map> 
  4. #include <utility> 
  5. #include <execinfo.h> 
  6. #include <errno.h> 
  7. #include  <assert.h> 
  8. #include <cxxabi.h> 
  9. #include <sys/types.h> 
  10. #include <unistd.h> 
  11. #include <stdlib.h> 
  12. #include "leakmon.h" 
  13.  
  14. CMutexLock gLock ; 
  15. std::map <void*, _PtrInfo> gPtrInfo ; 
  16. std::map <const LmCallStack*, _AllocInfo ,  __comp> gLeakInfo; 
  17.  
  18.  
  19. const int LmCallStack:: MAX_STACK_LAYERS = 32; 
  20.  
  21. /* Prototypes for our hooks. */ 
  22. static void my_init_hook ( void); 
  23. static void *my_malloc_hook ( size_t, const void *); 
  24. static void my_free_hook ( void*, const void *); 
  25.  
  26. void *(*__MALLOC_HOOK_VOLATILE old_malloc_hook)( size_t __size , const void *) ; 
  27. void (*__MALLOC_HOOK_VOLATILE old_free_hook) ( void *__ptr , const void *); 
  28. /* Override initializing hook from the C library. */ 
  29. void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook) ( void) = my_init_hook; 
  30.  
  31. void my_init_hook (void) 
  32. { 
  33.     old_malloc_hook = __malloc_hook ; 
  34.     old_free_hook = __free_hook ; 
  35.     __malloc_hook = my_malloc_hook ; 
  36.     __free_hook = my_free_hook ; 
  37. } 
  38.  
  39. static void *my_malloc_hook ( size_t size , const void *caller ) 
  40. { 
  41.     void *result ; 
  42.        gLock.lock (); 
  43.     /* Restore all old hooks */ 
  44.     __malloc_hook = old_malloc_hook ; 
  45.     __free_hook = old_free_hook ; 
  46.     /* Call recursively */ 
  47.     result = malloc (size); 
  48.     /* Save underlying hooks */ 
  49.     old_malloc_hook = __malloc_hook ; 
  50.     old_free_hook = __free_hook ; 
  51.     /* printf might call malloc, so protect it too. */ 
  52.     //printf ("malloc (%u) returns %p\n", (unsigned int) size, result); 
  53.        RecordPtr( result , size); 
  54.  
  55.     /* Restore our own hooks */ 
  56.     __malloc_hook = my_malloc_hook ; 
  57.     __free_hook = my_free_hook ; 
  58.        gLock.unlock (); 
  59.     return result ; 
  60. } 
  61.  
  62. static void my_free_hook ( void *ptr , const void *caller ) 
  63. { 
  64.        gLock.lock (); 
  65.     /* Restore all old hooks */ 
  66.     __malloc_hook = old_malloc_hook ; 
  67.     __free_hook = old_free_hook ; 
  68.     /* Call recursively */ 
  69.     free (ptr ); 
  70.     /* Save underlying hooks */ 
  71.     old_malloc_hook = __malloc_hook ; 
  72.     old_free_hook = __free_hook ; 
  73.     /* printf might call free, so protect it too. */ 
  74.     //printf ("freed pointer %p\n", ptr); 
  75.  
  76.        RemovePtr( ptr ); 
  77.  
  78.     /* Restore our own hooks */ 
  79.     __malloc_hook = my_malloc_hook ; 
  80.     __free_hook = my_free_hook ; 
  81.        gLock.unlock (); 
  82. } 
  83.  
  84. void RecordPtr ( void* ptr, size_t size) 
  85. { 
  86.        // 獲取調用棧 
  87.        void *array [LmCallStack:: MAX_STACK_LAYERS]; 
  88.        int cstSize = backtrace( array, LmCallStack ::MAX_STACK_LAYERS); 
  89.  
  90.        // 保存指針 調用棧 
  91.        LmCallStack* callstack = new LmCallStack(array , cstSize); 
  92.  
  93.        gLock.lock (); 
  94.  
  95.        std::map <const LmCallStack*, _AllocInfo ,  __comp>:: iterator it = gLeakInfo.find (callstack); 
  96.        if (it != gLeakInfo. end()) 
  97.       { 
  98.              it->second .size += size; 
  99.              it->second .alloc++; 
  100.  
  101.              _PtrInfo pi (it-> first, size ); 
  102.              gPtrInfo[ptr ] = pi; 
  103.       } 
  104.        else 
  105.       { 
  106.              _AllocInfo aif (size, 1, 0); 
  107.              std::pair <std:: map<const LmCallStack*, _AllocInfo,  __comp>::iterator , bool> ret = gLeakInfo .insert( std::pair <const LmCallStack*, _AllocInfo >(callstack, aif)); 
  108.              
  109.              if (ret .second) 
  110.             { 
  111.                    _PtrInfo pi (ret. first->first , size); 
  112.                    gPtrInfo[ptr ] = pi; 
  113.             } 
  114.              else 
  115.             { 
  116.                    // failed 
  117.             } 
  118.       } 
  119.  
  120.        gLock.unlock (); 
  121. } 
  122.  
  123. void RemovePtr ( void* ptr ) 
  124. { 
  125.        gLock.lock (); 
  126.  
  127.        std::map <void*, _PtrInfo>::iterator it = gPtrInfo.find (ptr); 
  128.        if (it != gPtrInfo. end()) 
  129.       { 
  130.              std::map <const LmCallStack*, _AllocInfo ,  __comp>:: iterator itc = gLeakInfo .find( it->second .csk); 
  131.              if (itc != gLeakInfo. end()) 
  132.             { 
  133.                    itc->second .size -= it->second .size; 
  134.                    itc->second .free++; 
  135.  
  136.                    if (0 == (itc ->second. alloc - itc ->second. free)) 
  137.                   { 
  138.                          assert(0 == itc ->second. size); 
  139.                          delete itc ->first; 
  140.                          gLeakInfo.erase (itc); 
  141.                   } 
  142.             } 
  143.  
  144.              gPtrInfo.erase (it); 
  145.       } 
  146.  
  147.        gLock.unlock (); 
  148. } 
  149.  
  150. void Report () 
  151. { 
  152.        char **strings = NULL; 
  153.        gLock.lock (); 
  154.  
  155.        __malloc_hook = old_malloc_hook ; 
  156.     __free_hook = old_free_hook ; 
  157.  
  158.        for (std ::map< const LmCallStack *, _AllocInfo,  __comp>::iterator it = gLeakInfo .begin(); 
  159.              it != gLeakInfo .end(); 
  160.              it++) 
  161.       { 
  162.              printf("\n" ); 
  163.              printf("====>  size: %ld,  allocs: %d,  frees: %d, a-f: %d\n", it-> second.size , it-> second.alloc , it-> second.free , it->second .alloc- it->second .free ); 
  164.              printf("====>  stacks back trace:\n" ); 
  165.              strings = backtrace_symbols ((void**) it->first ->callstack, it->first ->size); 
  166.              if (strings ) 
  167.             { 
  168.                    for(int i = 2; i < it ->first-> size; i ++) 
  169.                   { //printf("     %s\n", strings[i]); 
  170.                          char output [1024] = {0}; 
  171.                          memset(output , 0, 1024); 
  172.                          char temp [1024] = {0}; 
  173.                          memset(temp , 0, 1024); 
  174.                          //// 
  175.                          ////    get real function name 
  176.                          //// 
  177.                          if (1 == sscanf (strings[ i], "%*[^(]%*[^_]%[^)+]" , temp)) 
  178.                         { 
  179.                                      int status ; 
  180.                                      char* realname = abi::__cxa_demangle (temp, 0, 0, & status); 
  181.                                      if (0 == status ) 
  182.                                     { 
  183.                                            char* p = strchr( strings[i ], '('); 
  184.                                            memcpy(output , strings[ i], p-strings [i]); 
  185.                                            sprintf(output +(p- strings[i ]), "(%s+%p) " , realname, (( void**)it ->first-> callstack)[i ]); //printf("     -%s\n", realname); 
  186.                                            free(realname ); 
  187.                                     } 
  188.                                      else 
  189.                                     { 
  190.                                            char* p = strchr( strings[i ], ')'); 
  191.                                            memcpy(output , strings[ i], p-strings [i]+2); 
  192.                                     } 
  193.                         } 
  194.                          else 
  195.                         { 
  196.                                char* p = strchr( strings[i ], ')'); 
  197.                                memcpy(output , strings[ i], p-strings [i]+2); 
  198.                         } 
  199.  
  200.                          FILE * fp ; 
  201.                          char module [1024] = {0}; 
  202.                          memset(module , 0, 1024); 
  203.                          char* pm = strchr( strings[i ], '('); 
  204.                          memcpy(module , strings[ i], pm -strings[ i]); 
  205.  
  206.                          if (strstr (module, ".so")) 
  207.                         { 
  208.                                __pid_t pid = getpid(); 
  209.                                sprintf(temp , "grep %s /proc/%d/maps", module, pid ); 
  210.                                /// 
  211.                                ///         get library base-map-address 
  212.                                /// 
  213.                                fp = popen (temp, "r"); 
  214.                                if (fp ) 
  215.                               { 
  216.                                      char baseaddr [64]; 
  217.                                      unsigned long long base; 
  218.                                      
  219.                                      fgets(temp , sizeof( temp)-1, fp );  //printf("memmap: %s\n", temp); 
  220.                                      sscanf(temp , "%[^-]", baseaddr); 
  221.                                      base = strtoll (baseaddr, NULL, 16); //printf("baseaddr:%s\n", baseaddr); //printf(" base:0x%llx\n", base); 
  222.  
  223.                                      sprintf(temp , "addr2line -e %s %p", module, (void *)((unsigned long long)((void **)it-> first->callstack )[i]- base)); 
  224.                               } 
  225.                         } 
  226.                          else 
  227.                         { 
  228.                                sprintf(temp , "addr2line -e %s %p", module, ((void **)it-> first->callstack )[i]); 
  229.                         } 
  230.                          //// 
  231.                          ////    get source file name and line number 
  232.                          //// 
  233.                          fp = popen (temp, "r");  //printf("cmdline: %s\n", temp); 
  234.                          if (fp ) 
  235.                         { 
  236.                                fgets(temp , sizeof( temp)-1, fp ); //printf("     -%s\n", temp); 
  237.  
  238.                                strcat(output , temp); 
  239.                                printf("   ->  %s" , output); 
  240.                                pclose(fp ); 
  241.                         } 
  242.                          else 
  243.                         { 
  244.                                printf("   ->  %s\n" , output); 
  245.                         } 
  246.                   } 
  247.  
  248.                    free(strings ); 
  249.                    strings = NULL ; 
  250.             } 
  251.       } 
  252.  
  253.        __malloc_hook = my_malloc_hook ; 
  254.     __free_hook = my_free_hook ; 
  255.  
  256.        gLock.unlock (); 
  257. } 
  258.  
  259.  
  260. ////////////////////////////////////////////////////////////////////////// 
  261.  
  262. CMutexLock::CMutexLock () 
  263. { 
  264.        pthread_mutexattr_t  m_attr ; 
  265.        pthread_mutexattr_init(&m_attr ); 
  266.        pthread_mutexattr_settype(&m_attr , PTHREAD_MUTEX_RECURSIVE); 
  267.  
  268.        if (0 != pthread_mutex_init (&m_mutex , & m_attr)) 
  269.       { 
  270.              printf("c_lock::c_lock pthread_mutex_init error<%d>.\n" , errno); 
  271.              assert(0); 
  272.       } 
  273.  
  274.        pthread_mutexattr_destroy(&m_attr ); 
  275. } 
  276.  
  277. CMutexLock::~CMutexLock () 
  278. { 
  279.        if(0 != pthread_mutex_destroy (&m_mutex)) 
  280.       { 
  281.              printf("c_lock::~c_lock pthread_mutex_destroy error<%d>.\n" , errno); 
  282.              assert(0); 
  283.       } 
  284. } 
  285.  
  286. void 
  287. CMutexLock::lock () 
  288. { 
  289.  
  290.        if(0 != pthread_mutex_lock (&m_mutex)) 
  291.       { 
  292.              assert("c_lock::lock pthread_mutex_lock " && 0); 
  293.       } 
  294. } 
  295.  
  296. void 
  297. CMutexLock::unlock () 
  298. { 
  299.        int iRet = 0; 
  300.  
  301.        if(0 != (iRet = pthread_mutex_unlock(& m_mutex))) 
  302.       { 
  303.              printf("c_lock::unlock pthread_mutex_unlock ret<%d> error<%d>.\n", iRet, errno ); 
  304.              assert(0); 
  305.       } 
  306. } 
  307.  
  308. 示例代碼: 
  309. leakmom.h 
  310.  
  311. //////////////////////////////////////////////////////////////////////// 
  312. // 
  313. //    The Executable file MUST be linked with parameter '-rdynamic' !!! 
  314. // 
  315. //////////////////////////////////////////////////////////////////////// 
  316.  
  317. #pragma once 
  318. #include <string.h> 
  319. #include <pthread.h> 
  320.                          
  321. // 
  322. class LmCallStack 
  323. { 
  324. public: 
  325.        char* callstack ; // pointer to buffer recording callstack addresses 
  326.        int size ; // count of call stacks 
  327.        static const int MAX_STACK_LAYERS; 
  328. public: 
  329.        LmCallStack(void * csk= NULL, int s=0) 
  330.       { 
  331.              if (csk ) 
  332.             { 
  333.                    callstack = new char[ s*sizeof (void*)]; 
  334.                    memcpy(callstack , csk, s*sizeof (void*)); 
  335.             } 
  336.              else 
  337.             { 
  338.                    callstack = (char *)csk; 
  339.             } 
  340.              size = s ; 
  341.       } 
  342.  
  343.       ~ LmCallStack() 
  344.       { 
  345.              if (callstack ) 
  346.             { 
  347.                    delete[] callstack ; 
  348.             } 
  349.              callstack = NULL ; 
  350.              size = 0; 
  351.       } 
  352. }; 
  353.  
  354. class __comp 
  355. { 
  356. public: 
  357.        __comp(){}; 
  358.        bool operator () (const LmCallStack* first , const LmCallStack* second) 
  359.       { 
  360.              return ((first ->size < second->size ) || 
  361.                         ( first->size == second-> size && 
  362.                                      memcmp(first ->callstack, second->callstack , sizeof( void*)*first ->size) < 0) 
  363.                         ); 
  364.       } 
  365. }; 
  366.  
  367. struct _PtrInfo 
  368. { 
  369.        _PtrInfo(const LmCallStack* c=NULL , long s=0) 
  370.       { 
  371.              csk = c ; 
  372.              size = s ; 
  373.       } 
  374.        const LmCallStack * csk; 
  375.        long size ; 
  376. }; 
  377.  
  378. struct _AllocInfo 
  379. { 
  380.        _AllocInfo(long s=0, int a =0, int f=0) 
  381.       { 
  382.              size=s ; 
  383.              alloc=a ; 
  384.              free=f ; 
  385.       } 
  386.        // 
  387.        long size ; 
  388.        int alloc ; 
  389.        int free ; 
  390. }; 
  391.  
  392. class CMutexLock 
  393. { 
  394. public: 
  395.        CMutexLock(); 
  396.       ~ CMutexLock(); 
  397.  
  398. public: 
  399.        void lock (); 
  400.        void unlock (); 
  401.  
  402. private: 
  403.        pthread_mutex_t m_mutex ; 
  404. }; 
  405.  
  406.  
  407. // 
  408. void RecordPtr ( void* ptr, size_t size); 
  409. void RemovePtr (void* ptr); 
  410. void Report (); 
     



  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved