草庐IT

c++ - 如何在 C++ 中查找内存泄漏

coder 2023-11-16 原文

在嵌入式环境中检测 C++ 内存泄漏的好方法是什么?我尝试过重载 new 运算符来记录每个数据分配,但我一定做错了什么,这种方法不起作用。有没有其他人遇到过类似情况?

这是重载 new 和 delete 运算符的代码。

编辑:

完全披露:我正在寻找我的程序中的内存泄漏,并且我正在使用其他人编写的这段代码来重载 new 和 delete 运算符。我的部分问题是我不完全理解它的作用。我知道目标是记录调用者和前一个调用者的地址,分配的大小,如果我们正在分配,则为 1,如果我们正在取消分配,则为 2。加上正在运行的线程的名称。

感谢所有建议,我将尝试工作中有人建议的不同方法。如果有效,我会在这里发布。

再次感谢所有一流的程序员花时间回答。

StackOverflow 棒极了!

结论

谢谢大家的回答。不幸的是,我不得不继续讨论另一个更紧迫的问题。此泄漏仅在极不可能的情况下发生。我觉得放弃它很糟糕,如果我有更多时间,我可能会回到它。我选择了我最有可能使用的答案。

#include <stdlib.h>
#include "stdio.h"
#include "nucleus.h"
#include "plus/inc/dm_defs.h"
#include "plus/inc/pm_defs.h"

#include "posix\inc\posix.h"

extern void* TCD_Current_Thread;
extern "C" void rd_write_text(char * text);
extern PM_PCB * PMD_Created_Pools_List;

typedef struct {
    void* addr;
    uint16_t size;
    uint16_t flags;
} MemLogEntryNarrow_t;

typedef struct {
    void* addr;
    uint16_t size;
    uint16_t flags;
    void* caller;
    void* prev_caller;
    void* taskid;
    uint32_t timestamp;
} MemLogEntryWide_t;

//size lookup table
unsigned char MEM_bitLookupTable[] = {
 0,1,1,2,1,2,2,3,1,2,2,3,1,3,3,4
};

//#pragma CODE_SECTION ("section_ramset1_0")
void *::operator new(unsigned int size)
{
   asm(" STR R14, [R13, #0xC]");  //save stack address temp[0]
   asm(" STR R13, [R13, #0x10]");  //save pc return address temp[1]

   if ( loggingEnabled )
   {
      uint32_t savedInterruptState;
      uint32_t currentIndex;

      // protect the thread unsafe section.
      savedInterruptState = NU_Local_Control_Interrupts(NU_DISABLE_INTERRUPTS);

      // Note that this code is FRAGILE.  It peeks backwards on the stack to find the return
      // address of the caller.  The location of the return address on the stack can be easily changed
      // as a result of other changes in this function (i.e. adding local variables, etc).
      // The offsets may need to be adjusted if this function is touched.
      volatile unsigned int temp[2];

      unsigned int *addr = (unsigned int *)temp[0] - 1;
      unsigned int count = 1 + (0x20/4);   //current stack space ***

      //Scan for previous store
      while ((*addr & 0xFFFF0000) != 0xE92D0000)
      {
         if ((*addr & 0xFFFFF000) == 0xE24DD000)
         {
            //add offset in words
            count += ((*addr & 0xFFF) >> 2);
         }
         addr--;
      }

      count += MEM_bitLookupTable[*addr & 0xF];
      count += MEM_bitLookupTable[(*addr >>4) & 0xF];
      count += MEM_bitLookupTable[(*addr >> 8) & 0xF];
      count += MEM_bitLookupTable[(*addr >> 12) & 0xF];

      addr = (unsigned int *)temp[1] + count;
      // FRAGILE CODE ENDS HERE

      currentIndex = currentMemLogWriteIndex;
      currentMemLogWriteIndex++;

      if ( memLogNarrow )
      {
         if (currentMemLogWriteIndex >= MEMLOG_SIZE/2 )
         {
            loggingEnabled = false;
            rd_write_text( "Allocation Logging is complete and DISABLED!\r\n\r\n");
         }
         // advance the read index if necessary.
         if ( currentMemLogReadIndex == currentMemLogWriteIndex )
         {
            currentMemLogReadIndex++;
            if ( currentMemLogReadIndex == MEMLOG_SIZE/2 )
            {
               currentMemLogReadIndex = 0;
            }
         }

         NU_Local_Control_Interrupts(savedInterruptState);

         //Standard operator 
         //(For Partition Analysis we have to consider that if we alloc size of 0 always as size of 1 then are partitions must be optimized for this)
         if (size == 0) size = 1;

         ((MemLogEntryNarrow_t*)memLog)[currentIndex].size = size;
         ((MemLogEntryNarrow_t*)memLog)[currentIndex].flags = 1;    //allocated

         //Standard operator
         void * ptr;
         ptr = malloc(size);

         ((MemLogEntryNarrow_t*)memLog)[currentIndex].addr = ptr;

         return ptr;
      }
      else
      {
         if (currentMemLogWriteIndex >= MEMLOG_SIZE/6 )
         {
            loggingEnabled = false;
            rd_write_text( "Allocation Logging is complete and DISABLED!\r\n\r\n");
         }
         // advance the read index if necessary.
         if ( currentMemLogReadIndex == currentMemLogWriteIndex )
         {
            currentMemLogReadIndex++;
            if ( currentMemLogReadIndex == MEMLOG_SIZE/6 )
            {
               currentMemLogReadIndex = 0;
            }
         }

         ((MemLogEntryWide_t*)memLog)[currentIndex].caller = (void *)(temp[0] - 4);
         ((MemLogEntryWide_t*)memLog)[currentIndex].prev_caller = (void *)*addr;
         NU_Local_Control_Interrupts(savedInterruptState);
         ((MemLogEntryWide_t*)memLog)[currentIndex].taskid = (void *)TCD_Current_Thread;
         ((MemLogEntryWide_t*)memLog)[currentIndex].size = size;
         ((MemLogEntryWide_t*)memLog)[currentIndex].flags = 1;    //allocated
         ((MemLogEntryWide_t*)memLog)[currentIndex].timestamp = *(volatile uint32_t *)0xfffbc410;   // for arm9

         //Standard operator
         if (size == 0) size = 1;

         void * ptr;
         ptr = malloc(size);

         ((MemLogEntryWide_t*)memLog)[currentIndex].addr = ptr;

         return ptr;
      }
   }
   else
   {
       //Standard operator
       if (size == 0) size = 1;

       void * ptr;
       ptr = malloc(size);

       return ptr;
   }
}
//#pragma CODE_SECTION ("section_ramset1_0")
void ::operator delete(void *ptr)
{
   uint32_t savedInterruptState;
   uint32_t currentIndex;

   asm(" STR R14, [R13, #0xC]");  //save stack address temp[0]
   asm(" STR R13, [R13, #0x10]");  //save pc return address temp[1]

   if ( loggingEnabled )
   {
      savedInterruptState = NU_Local_Control_Interrupts(NU_DISABLE_INTERRUPTS);

      // Note that this code is FRAGILE.  It peeks backwards on the stack to find the return
      // address of the caller.  The location of the return address on the stack can be easily changed
      // as a result of other changes in this function (i.e. adding local variables, etc).
      // The offsets may need to be adjusted if this function is touched.
      volatile unsigned int temp[2];

      unsigned int *addr = (unsigned int *)temp[0] - 1;
      unsigned int count = 1 + (0x20/4);   //current stack space ***

      //Scan for previous store
      while ((*addr & 0xFFFF0000) != 0xE92D0000)
      {
         if ((*addr & 0xFFFFF000) == 0xE24DD000)
         {
            //add offset in words
            count += ((*addr & 0xFFF) >> 2);
         }
         addr--;
      }

      count += MEM_bitLookupTable[*addr & 0xF];
      count += MEM_bitLookupTable[(*addr >>4) & 0xF];
      count += MEM_bitLookupTable[(*addr >> 8) & 0xF];
      count += MEM_bitLookupTable[(*addr >> 12) & 0xF];

      addr = (unsigned int *)temp[1] + count;
      // FRAGILE CODE ENDS HERE

      currentIndex = currentMemLogWriteIndex;
      currentMemLogWriteIndex++;

      if ( memLogNarrow )
      {
         if ( currentMemLogWriteIndex >= MEMLOG_SIZE/2 )
         {
            loggingEnabled = false;
            rd_write_text( "Allocation Logging is complete and DISABLED!\r\n\r\n");
         }
         // advance the read index if necessary.
         if ( currentMemLogReadIndex == currentMemLogWriteIndex )
         {
            currentMemLogReadIndex++;
            if ( currentMemLogReadIndex == MEMLOG_SIZE/2 )
            {
               currentMemLogReadIndex = 0;
            }
         }

         NU_Local_Control_Interrupts(savedInterruptState);

         // finish logging the fields.  these are thread safe so they dont need to be inside the protected section.
         ((MemLogEntryNarrow_t*)memLog)[currentIndex].addr = ptr;
         ((MemLogEntryNarrow_t*)memLog)[currentIndex].size = 0;
         ((MemLogEntryNarrow_t*)memLog)[currentIndex].flags = 2;    //unallocated
      }
      else
      {
         ((MemLogEntryWide_t*)memLog)[currentIndex].caller = (void *)(temp[0] - 4);
         ((MemLogEntryWide_t*)memLog)[currentIndex].prev_caller = (void *)*addr;

         if ( currentMemLogWriteIndex >= MEMLOG_SIZE/6 )
         {
            loggingEnabled = false;
            rd_write_text( "Allocation Logging is complete and DISABLED!\r\n\r\n");
         }
         // advance the read index if necessary.
         if ( currentMemLogReadIndex == currentMemLogWriteIndex )
         {
            currentMemLogReadIndex++;
            if ( currentMemLogReadIndex == MEMLOG_SIZE/6 )
            {
               currentMemLogReadIndex = 0;
            }
         }
         NU_Local_Control_Interrupts(savedInterruptState);

         // finish logging the fields.  these are thread safe so they dont need to be inside the protected section.
         ((MemLogEntryWide_t*)memLog)[currentIndex].addr = ptr;
         ((MemLogEntryWide_t*)memLog)[currentIndex].size = 0;
         ((MemLogEntryWide_t*)memLog)[currentIndex].flags = 2;    //unallocated
         ((MemLogEntryWide_t*)memLog)[currentIndex].taskid = (void *)TCD_Current_Thread;
         ((MemLogEntryWide_t*)memLog)[currentIndex].timestamp = *(volatile uint32_t *)0xfffbc410;   // for arm9
      }

      //Standard operator
      if (ptr != NULL) {
         free(ptr);
      }
   }
   else
   {
      //Standard operator
      if (ptr != NULL) {
        free(ptr);
      }
   }
}

最佳答案

如果您运行的是 Linux,我建议尝试 Valgrind .

关于c++ - 如何在 C++ 中查找内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/996498/

有关c++ - 如何在 C++ 中查找内存泄漏的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. ruby-on-rails - Ruby net/ldap 模块中的内存泄漏 - 2

    作为我的Rails应用程序的一部分,我编写了一个小导入程序,它从我们的LDAP系统中吸取数据并将其塞入一个用户表中。不幸的是,与LDAP相关的代码在遍历我们的32K用户时泄漏了大量内存,我一直无法弄清楚如何解决这个问题。这个问题似乎在某种程度上与LDAP库有关,因为当我删除对LDAP内容的调用时,内存使用情况会很好地稳定下来。此外,不断增加的对象是Net::BER::BerIdentifiedString和Net::BER::BerIdentifiedArray,它们都是LDAP库的一部分。当我运行导入时,内存使用量最终达到超过1GB的峰值。如果问题存在,我需要找到一些方法来更正我的代

  3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  4. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  5. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  6. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  7. ruby - 如何在续集中重新加载表模式? - 2

    鉴于我有以下迁移:Sequel.migrationdoupdoalter_table:usersdoadd_column:is_admin,:default=>falseend#SequelrunsaDESCRIBEtablestatement,whenthemodelisloaded.#Atthispoint,itdoesnotknowthatusershaveais_adminflag.#Soitfails.@user=User.find(:email=>"admin@fancy-startup.example")@user.is_admin=true@user.save!ende

  8. ruby - 如何在 Ruby 中拆分参数字符串 Bash 样式? - 2

    我正在为一个项目制作一个简单的shell,我希望像在Bash中一样解析参数字符串。foobar"helloworld"fooz应该变成:["foo","bar","helloworld","fooz"]等等。到目前为止,我一直在使用CSV::parse_line,将列分隔符设置为""和.compact输出。问题是我现在必须选择是要支持单引号还是双引号。CSV不支持超过一个分隔符。Python有一个名为shlex的模块:>>>shlex.split("Test'helloworld'foo")['Test','helloworld','foo']>>>shlex.split('Test"

  9. ruby - 如何在 Lion 上安装 Xcode 4.6,需要用 RVM 升级 ruby - 2

    我实际上是在尝试使用RVM在我的OSX10.7.5上更新ruby,并在输入以下命令后:rvminstallruby我得到了以下回复:Searchingforbinaryrubies,thismighttakesometime.Checkingrequirementsforosx.Installingrequirementsforosx.Updatingsystem.......Errorrunning'requirements_osx_brew_update_systemruby-2.0.0-p247',pleaseread/Users/username/.rvm/log/138121

  10. ruby-on-rails - 如何在 ruby​​ 交互式 shell 中有多行? - 2

    这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式ruby​​shell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f

随机推荐