中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Linux下c++程序內存泄漏檢測代碼的示例分析

發布時間:2021-10-29 18:28:09 來源:億速云 閱讀:167 作者:柒染 欄目:編程語言

這期內容當中小編將會給大家帶來有關如何解決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

/* Prototypes for __malloc_hook, __free_hook */ #include <malloc.h> #include <map> #include <utility> #include <execinfo.h> #include <errno.h> #include  <assert.h> #include <cxxabi.h> #include <sys/types.h> #include <unistd.h> #include <stdlib.h> #include "leakmon.h"  CMutexLock gLock ; std::map <void*, _PtrInfo> gPtrInfo ; std::map <const LmCallStack*, _AllocInfo ,  __comp> gLeakInfo;   const int LmCallStack:: MAX_STACK_LAYERS = 32;  /* Prototypes for our hooks. */ static void my_init_hook ( void); static void *my_malloc_hook ( size_t, const void *); static void my_free_hook ( void*, const void *);  void *(*__MALLOC_HOOK_VOLATILE old_malloc_hook)( size_t __size , const void *) ; void (*__MALLOC_HOOK_VOLATILE old_free_hook) ( void *__ptr , const void *); /* Override initializing hook from the C library. */ void (*__MALLOC_HOOK_VOLATILE __malloc_initialize_hook) ( void) = my_init_hook;  void my_init_hook (void) {     old_malloc_hook = __malloc_hook ;     old_free_hook = __free_hook ;     __malloc_hook = my_malloc_hook ;     __free_hook = my_free_hook ; }  static void *my_malloc_hook ( size_t size , const void *caller ) {     void *result ;        gLock.lock ();     /* Restore all old hooks */     __malloc_hook = old_malloc_hook ;     __free_hook = old_free_hook ;     /* Call recursively */     result = malloc (size);     /* Save underlying hooks */     old_malloc_hook = __malloc_hook ;     old_free_hook = __free_hook ;     /* printf might call malloc, so protect it too. */     //printf ("malloc (%u) returns %p\n", (unsigned int) size, result);        RecordPtr( result , size);      /* Restore our own hooks */     __malloc_hook = my_malloc_hook ;     __free_hook = my_free_hook ;        gLock.unlock ();     return result ; }  static void my_free_hook ( void *ptr , const void *caller ) {        gLock.lock ();     /* Restore all old hooks */     __malloc_hook = old_malloc_hook ;     __free_hook = old_free_hook ;     /* Call recursively */     free (ptr );     /* Save underlying hooks */     old_malloc_hook = __malloc_hook ;     old_free_hook = __free_hook ;     /* printf might call free, so protect it too. */     //printf ("freed pointer %p\n", ptr);         RemovePtr( ptr );      /* Restore our own hooks */     __malloc_hook = my_malloc_hook ;     __free_hook = my_free_hook ;        gLock.unlock (); }  void RecordPtr ( void* ptr, size_t size) {        // 獲取調用棧        void *array [LmCallStack:: MAX_STACK_LAYERS];        int cstSize = backtrace( array, LmCallStack ::MAX_STACK_LAYERS);         // 保存指針 調用棧        LmCallStack* callstack = new LmCallStack(array , cstSize);         gLock.lock ();         std::map <const LmCallStack*, _AllocInfo ,  __comp>:: iterator it = gLeakInfo.find (callstack);        if (it != gLeakInfo. end())       {              it->second .size += size;              it->second .alloc++;               _PtrInfo pi (it-> first, size );              gPtrInfo[ptr ] = pi;       }        else       {              _AllocInfo aif (size, 1, 0);              std::pair <std:: map<const LmCallStack*, _AllocInfo,  __comp>::iterator , bool> ret = gLeakInfo .insert( std::pair <const LmCallStack*, _AllocInfo >(callstack, aif));                           if (ret .second)             {                    _PtrInfo pi (ret. first->first , size);                    gPtrInfo[ptr ] = pi;             }              else             {                    // failed             }       }         gLock.unlock (); }  void RemovePtr ( void* ptr ) {        gLock.lock ();         std::map <void*, _PtrInfo>::iterator it = gPtrInfo.find (ptr);        if (it != gPtrInfo. end())       {              std::map <const LmCallStack*, _AllocInfo ,  __comp>:: iterator itc = gLeakInfo .find( it->second .csk);              if (itc != gLeakInfo. end())             {                    itc->second .size -= it->second .size;                    itc->second .free++;                     if (0 == (itc ->second. alloc - itc ->second. free))                   {                          assert(0 == itc ->second. size);                          delete itc ->first;                          gLeakInfo.erase (itc);                   }             }               gPtrInfo.erase (it);       }         gLock.unlock (); }  void Report () {        char **strings = NULL;        gLock.lock ();         __malloc_hook = old_malloc_hook ;     __free_hook = old_free_hook ;         for (std ::map< const LmCallStack *, _AllocInfo,  __comp>::iterator it = gLeakInfo .begin();              it != gLeakInfo .end();              it++)       {              printf("\n" );              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 );              printf("====>  stacks back trace:\n" );              strings = backtrace_symbols ((void**) it->first ->callstack, it->first ->size);              if (strings )             {                    for(int i = 2; i < it ->first-> size; i ++)                   { //printf("     %s\n", strings[i]);                          char output [1024] = {0};                          memset(output , 0, 1024);                          char temp [1024] = {0};                          memset(temp , 0, 1024);                          ////                          ////    get real function name                          ////                          if (1 == sscanf (strings[ i], "%*[^(]%*[^_]%[^)+]" , temp))                         {                                      int status ;                                      char* realname = abi::__cxa_demangle (temp, 0, 0, & status);                                      if (0 == status )                                     {                                            char* p = strchr( strings[i ], '(');                                            memcpy(output , strings[ i], p-strings [i]);                                            sprintf(output +(p- strings[i ]), "(%s+%p) " , realname, (( void**)it ->first-> callstack)[i ]); //printf("     -%s\n", realname);                                            free(realname );                                     }                                      else                                     {                                            char* p = strchr( strings[i ], ')');                                            memcpy(output , strings[ i], p-strings [i]+2);                                     }                         }                          else                         {                                char* p = strchr( strings[i ], ')');                                memcpy(output , strings[ i], p-strings [i]+2);                         }                           FILE * fp ;                          char module [1024] = {0};                          memset(module , 0, 1024);                          char* pm = strchr( strings[i ], '(');                          memcpy(module , strings[ i], pm -strings[ i]);                           if (strstr (module, ".so"))                         {                                __pid_t pid = getpid();                                sprintf(temp , "grep %s /proc/%d/maps", module, pid );                                ///                                ///         get library base-map-address                                ///                                fp = popen (temp, "r");                                if (fp )                               {                                      char baseaddr [64];                                      unsigned long long base;                                                                           fgets(temp , sizeof( temp)-1, fp );  //printf("memmap: %s\n", temp);                                      sscanf(temp , "%[^-]", baseaddr);                                      base = strtoll (baseaddr, NULL, 16); //printf("baseaddr:%s\n", baseaddr); //printf(" base:0x%llx\n", base);                                       sprintf(temp , "addr2line -e %s %p", module, (void *)((unsigned long long)((void **)it-> first->callstack )[i]- base));                               }                         }                          else                         {                                sprintf(temp , "addr2line -e %s %p", module, ((void **)it-> first->callstack )[i]);                         }                          ////                          ////    get source file name and line number                          ////                          fp = popen (temp, "r");  //printf("cmdline: %s\n", temp);                          if (fp )                         {                                fgets(temp , sizeof( temp)-1, fp ); //printf("     -%s\n", temp);                                 strcat(output , temp);                                printf("   ->  %s" , output);                                pclose(fp );                         }                          else                         {                                printf("   ->  %s\n" , output);                         }                   }                     free(strings );                    strings = NULL ;             }       }         __malloc_hook = my_malloc_hook ;     __free_hook = my_free_hook ;         gLock.unlock (); }   //////////////////////////////////////////////////////////////////////////  CMutexLock::CMutexLock () {        pthread_mutexattr_t  m_attr ;        pthread_mutexattr_init(&m_attr );        pthread_mutexattr_settype(&m_attr , PTHREAD_MUTEX_RECURSIVE);         if (0 != pthread_mutex_init (&m_mutex , & m_attr))       {              printf("c_lock::c_lock pthread_mutex_init error<%d>.\n" , errno);              assert(0);       }         pthread_mutexattr_destroy(&m_attr ); }  CMutexLock::~CMutexLock () {        if(0 != pthread_mutex_destroy (&m_mutex))       {              printf("c_lock::~c_lock pthread_mutex_destroy error<%d>.\n" , errno);              assert(0);       } }  void CMutexLock::lock () {         if(0 != pthread_mutex_lock (&m_mutex))       {              assert("c_lock::lock pthread_mutex_lock " && 0);       } }  void CMutexLock::unlock () {        int iRet = 0;         if(0 != (iRet = pthread_mutex_unlock(& m_mutex)))       {              printf("c_lock::unlock pthread_mutex_unlock ret<%d> error<%d>.\n", iRet, errno );              assert(0);       } }  示例代碼: leakmom.h  //////////////////////////////////////////////////////////////////////// // //    The Executable file MUST be linked with parameter '-rdynamic' !!! // ////////////////////////////////////////////////////////////////////////  #pragma once #include <string.h> #include <pthread.h>                          // class LmCallStack { public:        char* callstack ; // pointer to buffer recording callstack addresses        int size ; // count of call stacks        static const int MAX_STACK_LAYERS; public:        LmCallStack(void * csk= NULL, int s=0)       {              if (csk )             {                    callstack = new char[ s*sizeof (void*)];                    memcpy(callstack , csk, s*sizeof (void*));             }              else             {                    callstack = (char *)csk;             }              size = s ;       }        ~ LmCallStack()       {              if (callstack )             {                    delete[] callstack ;             }              callstack = NULL ;              size = 0;       } };  class __comp { public:        __comp(){};        bool operator () (const LmCallStack* first , const LmCallStack* second)       {              return ((first ->size < second->size ) ||                         ( first->size == second-> size &&                                      memcmp(first ->callstack, second->callstack , sizeof( void*)*first ->size) < 0)                         );       } };  struct _PtrInfo {        _PtrInfo(const LmCallStack* c=NULL , long s=0)       {              csk = c ;              size = s ;       }        const LmCallStack * csk;        long size ; };  struct _AllocInfo {        _AllocInfo(long s=0, int a =0, int f=0)       {              size=s ;              alloc=a ;              free=f ;       }        //        long size ;        int alloc ;        int free ; };  class CMutexLock { public:        CMutexLock();       ~ CMutexLock();  public:        void lock ();        void unlock ();  private:        pthread_mutex_t m_mutex ; };   // void RecordPtr ( void* ptr, size_t size); void RemovePtr (void* ptr); void Report ();

上述就是小編為大家分享的如何解決Linux下c++程序內存泄漏檢測代碼了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

贵州省| 绥中县| 保德县| 邹平县| 沾益县| 聊城市| 宁城县| 宣化县| 安多县| 商河县| 峨山| 游戏| 张家港市| 黄骅市| 周至县| 闵行区| 阿图什市| 龙海市| 剑川县| 富平县| 博野县| 温州市| 武汉市| 克拉玛依市| 乌鲁木齐市| 涿州市| 伊金霍洛旗| 肥城市| 三台县| 安化县| 宜昌市| 漳州市| 张家口市| 宜兰市| 武定县| 吴川市| 鄂伦春自治旗| 淅川县| 阿克苏市| 昌乐县| 钟山县|