千家信息网

Linux下c++程序内存泄漏检测代码的示例分析

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这期内容当中小编将会给大家带来有关如何解决Linux下c++程序内存泄漏检测代码,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Linux下对于程序内存泄漏检测的方法
千家信息网最后更新 2026年11月03日Linux下c++程序内存泄漏检测代码的示例分析

这期内容当中小编将会给大家带来有关如何解决Linux下c++程序内存泄漏检测代码,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。

Linux下对于程序内存泄漏检测的方法很多,最常用的的莫过于使用valgrind工具。但是valgrind相当于让程序在虚拟机中运行,会带 来较大的系统资源开销,还会对程序的运行效率产生较大影响,对于那种资源占用大的程序,如果需要长时间运行才能暴露的泄漏问题,它就显得不太好用。

linux下的c++程序中自己实现一个轻量级的泄漏检测代码其实是比较方便的,下面我就给出一个简单的范例,并作简单的说明。当然,我们还是应该提倡使用共享指针,用共享指针自动管理内存可以避免内存泄漏这样的不必要的麻烦。

基本原理:

  • 利用glibc提供的__malloc_hook, __free_hook系列函数对内存分配是否做监控;(详见glibc的官方文档)

  • 利用backtrace函数获取函数调用栈,并记录;

  • 利用backtrace_symbols对调用栈对应的函数做解析;

进一步处理:

  • 使用abi::__cxa_demangle把函数名解析为源代码风格;

  • 使用addr2line解析出函数调用栈对应的代码行;

  • 对于动态库(.so)中的地址解析,需要先在/proc//maps文件中找到动态库映射的基地址,才能做解析。

注意:

编译连接参数中使用-g -rdynamic

以上每步具体实现的代码可能都没有达到***,甚至可能是笨办法,如果有更好的实现方案请直接替换,也欢迎赐教。

示例代码:

leakmom.cpp

/* Prototypes for __malloc_hook, __free_hook */ #include  #include  #include  #include  #include  #include   #include  #include  #include  #include  #include "leakmon.h"  CMutexLock gLock ; std::map  gPtrInfo ; std::map  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 :: 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 ::iterator , bool> ret = gLeakInfo .insert( std::pair (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 ::iterator it = gPtrInfo.find (ptr);        if (it != gPtrInfo. end())       {              std::map :: 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  #include                           // 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++程序内存泄漏检测代码了,如果刚好有类似的疑惑,不妨参照上述分析进行理解。如果想知道更多相关知识,欢迎关注行业资讯频道。

代码 程序 函数 内存 检测 c++ 指针 运行 示例 分析 较大 内容 动态 资源 中小 内容丰富 办法 原理 参数 地址 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 科技互联网项目 科技与互联网 互联网电商科技 互联网科技英文 致骋互联网科技 海南购全球互联网科技 栖莱科技互联网股份有限公司 互联网科技产业特征 链环科技传统企业怎么转型互联网 科技类公司包括互联网吗 朱啸虎曾投资哪些互联网科技企业 南通创西澳互联网科技有限公司 富国互联网金融科技混合基金 富国互联网科技002692 下一代互联网重大应用科技园 山东大美朱楼互联网科技有限公司 易企秀互联网科技是做什么的 上海乐五互联网科技有限公司 青岛互联网科技园 高科技和互联网的现代国家 科技互联网公司装修 科技互联网技术 顺玮阁互联网科技 兼蜜互联网科技 山东吉时兔互联网科技有限公司 南平创想时代互联网科技有限公司 移动互联网科技公司 互联网企业科技类企业如何做账 宁波跨境商互联网科技有限公司 互联网 科技节活动 微视频大赛
0