【问题标题】:How to check for memory leaks in a class in C++?如何在 C++ 中检查类中的内存泄漏?
【发布时间】:2014-03-24 16:03:22
【问题描述】:

我知道其他几个讨论过类似问题的线程。我也知道必须解除分配所有分配的资源,并且不应该留下任何东西。我问这个问题的原因是看看是否有一种方法可以自动检测类中的内存泄漏。特别是,我正在尝试实现一种自动化方法来检测单元测试中的泄漏,以便该类的未来开发更加健壮。由于我的类在其中使用了其他几个类以及一些 DLL,因此很难(如果不是不可能的话)跟踪所有这些中的泄漏,因此这样的单元测试可能会有所帮助。

我正在考虑几种能够检查类中的内存泄漏的解决方案。假设我的课程与此类似:

class MyClass
{
    MyClass() { /* Lots of allocations */ }
    ~MyClass() { /* Lots of deallocations */ }
}
  1. 在测试函数中,多次实例化类实例 并且每次都破坏。同时,检查任务管理器(在 Windows 至少)查看是否为您分配的内存 应用程序增加或基本保持平稳:

    TEST( MyClass, MyClass)
    {
        int some_big_number = 10000;
        for (int i=0; i<some_big_number; i++)
        {
            MyClass *myC = new MyClass;
            delete myC;
        }
    }
    
  2. 在实例化前后分配一些虚拟变量 销毁类实例并检查两个地址是否 相同。像这样的:

    TEST( MyClass, MyClass)
    {
        int address_1 = 0, address_2 = 0;
    
        int *tmp_1 = new int;
        address_1 = tmp_1;
        delete tmp_1;
    
        MyClass *myC = new MyClass;
        delete myC;
    
        int *tmp_2 = new int;
        address_2 = tmp_2;
        delete tmp_2;
    
        EXPECT_TRUE( address_1 == address_2 );
    }
    

    我的假设是,如果 MyClass 中没有内存泄漏,并且 所有声称的内存都已正确释放,地址 tmp_1 和 tmp_2 的值应该相同。我只是不确定记忆是否 分配就是这样工作的。

  3. 使用插件或程序,例如deleakerValgrind,但是 这可能会使我的代码或测试过大,我不确定是否 无论如何都可以在上面的上下文中使用。

谢谢!

【问题讨论】:

  • 根本无法保证 tmp_2 将获得相同的地址。这是底层分配器的实现相关细节。
  • valgrind.org怎么样
  • Also I am aware that one must deallocate all the allocated resources and nothing should be left unaccounted for 使用容器和智能指针等自动完成这项工作的构造怎么样?
  • 在创建被测类实例之前和之后使用内存使用比较,然后在调用被测类析构函数后再次使用内存使用情况如何?通过 Internet 快速搜索发现该站点有多种平台方法来查找正在使用的内存:C/C++ tip: How to get the process resident set size - physical memory use
  • 您应该告诉我们您使用的是什么 IDE。对于 Microsoft Visual Studio 项目,请尝试 vld.codeplex.com。微软内置的检漏仪很烂。

标签: c++ unit-testing memory memory-management memory-leaks


【解决方案1】:

@galop1n 是正确的,无论您在 general 中如何处理泄漏。

但您确实触及了一个有效点,即 DLL 内存管理。您会看到 DLL 中的对象需要以不同方式处理内存。您将内存管理委托给您的库。在您的库中,内存将按照它们定义的顺序分配。他们将提供释放此内存的方法(例如CUDA Libraries 中的cudaFree)。

你应该在对象的构造函数和析构函数中处理你的内存。 C++ 标准提供了一些很好的机制来为您处理内存。 unique_ptrshared_ptrC++11 中的一个很好的例子,你也可以使用来自 std 的容器来达到同样的目的。

Valgrind 也是一个很好的工具,一旦你已经完成了已经提到的所有事情。一旦你使用了C++ 提供的所有可能的工具,那么是时候用这个很棒的工具仔细检查你的内存使用了

【讨论】:

    【解决方案2】:

    如果您使用的是 VC++,VLD 又好又小,而且效果很好。

    【讨论】:

      【解决方案3】:

      你的第二个想法行不通,因为你不会每次都得到相同的地址。

      但是,您的第一个想法是一个好的开始,我将在此尝试改进。您可以通过调用GetProcessMemoryInfo() 自动执行该部分,而不是查看任务管理器。有关如何执行此操作的信息,请参阅this answer。您要在返回的数据结构中查看的值是 PrivateUsage。如果你在实例化你的类对象之前和在删除它之后再次这样做,你的内存使用应该是相同的。此外,如果您的类中的任何其他方法进行任何内存分配,您也需要在其中调用它们。这样,您的测试用例可以在没有任何人为干预的情况下为您的班级提供良好的锻炼,并且如果它检测到内存使用量正在上升,您可以让它做任何您想做的事情(记录一些东西、发出警报等等)。

      类似这样的:

      // Get the starting memory usage
      int baseline = GetMemoryUsage();   // This is the function that calls GetProcessMemoryInfo() as described in the link above
      
      MyClass *myC = new MyClass;
      int memUsage = GetMemoryUsage();
      myC->DoStuff();
      if (GetMemoryUsage() != memUsage)
          Alert("Detected memory leak in MyClass::DoStuff()");
      memUsage = GetMemoryUsage();
      myC->DoMoreStuff();
      if (GetMemoryUsage() != memUsage)
          Alert("Detected memory leak in MyClass::DoMoreStuff()");
      // ...
      // etc - call each method that does any kind of memory allocation
      // ...
      delete myC;
      if (GetMemoryUsage() != baseline)
          Alert("Detected memory leak in MyClass");
      


      要实现上面引用的 GetMemoryUsage() 函数,你可以这样做(我现在没有编译器,所以请原谅任何错别字):

      #include <windows.h>
      #include <psapi.h>
      #pragma comment(lib, "psapi.lib") 
      
      int GetMemoryUsage();
      {
          PROCESS_MEMORY_COUNTERS_EX pmc;
      
          DWORD processId = GetCurrentProcessId();
          HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
                                          PROCESS_VM_READ,
                                          FALSE, processID);
          if (hProcess == NULL)
              return -1;
      
          if (GetProcessMemoryInfo( hProcess, (PROCESS_MEMORY_COUNTERS *) &pmc, sizeof(pmc)))
          {
              CloseHandle(hProcess);
              return pmc.PrivateUsage;
          }
      
          CloseHandle(hProcess);
          return -1;
      }
      

      【讨论】:

      • 我会试一试,如果它对我有用,我会告诉你。我在哪里可以找到 GetMemoryUsage()?它不在您使用的语法中的 Psapi.h 中。 GetProcessMemoryInfo() 等其他函数需要一个我没有的进程句柄,因为我不知道 MyClass 中运行的所有线程。
      • 您需要根据我在答案中给您的链接实现 GetMemoryUsage() 。您将从 OpenProcess() 获得一个进程句柄,如代码示例中所示。线程在这里无关紧要 - 您正在获取进程信息
      • 我已经编辑了答案,为您提供 GetMemoryUsage() 的示例实现
      • 为了使用上面的函数,我必须在标题中添加以下内容:#include #include #pragma comment( lib, "psapi.lib" )
      • 很高兴它有帮助 - 我编辑了上面的代码以添加#includes,这样下一个遇到这篇文章的人会更容易
      【解决方案4】:

      您正在寻找的似乎是实用程序valgrind它提供了有关如何在程序中管理和释放内存的关键信息。

      在 valgrind.org 上查看

      【讨论】:

        猜你喜欢
        • 2022-01-23
        • 1970-01-01
        • 2016-08-08
        • 1970-01-01
        • 1970-01-01
        • 2013-01-26
        • 1970-01-01
        • 1970-01-01
        • 2013-02-03
        相关资源
        最近更新 更多