C++ 如何查找是否存在内存泄漏

C++ 如何查找是否存在内存泄漏,c++,memory-leaks,C++,Memory Leaks,我写了一个数字运算算法。其想法是: 一个小的主程序需要很少的内存(从2MB开始) 然后,在循环中,它调用一个需要相当多内存(大约100 MB)的函数,该内存应该在函数结束时释放。为了了解发生了什么,现在总是使用相同的参数调用函数 程序似乎在慢慢消耗内存,因此我怀疑内存泄漏。我试过Clang的地址消毒剂和Intel的指针检查器,但他们什么也没找到 现在,我正在查看活动监视器中的内存消耗情况(我运行的是OSX,但我从Unix命令“top”中获得了相同的内存使用情况),就在调用大函数之前,程序占用了2

我写了一个数字运算算法。其想法是:

  • 一个小的主程序需要很少的内存(从2MB开始)
  • 然后,在循环中,它调用一个需要相当多内存(大约100 MB)的函数,该内存应该在函数结束时释放。为了了解发生了什么,现在总是使用相同的参数调用函数
  • 程序似乎在慢慢消耗内存,因此我怀疑内存泄漏。我试过Clang的地址消毒剂和Intel的指针检查器,但他们什么也没找到

    现在,我正在查看活动监视器中的内存消耗情况(我运行的是OSX,但我从Unix命令“top”中获得了相同的内存使用情况),就在调用大函数之前,程序占用了2MB。运行该函数时,程序需要120 MB。奇怪的是,当程序结束大函数并返回到循环中时,它现在需要37MB!然后,当它回到大功能中时,需要130MB。再次,回到循环中,需要36MB,然后在大函数中需要140MB

    因此,它正在慢慢地漂移,但没有规律。我应该如何信任“top”中的内存使用情况

    内存碎片是否可以在没有内存泄漏的情况下提高内存使用率


    我让程序在一夜之间运行,下面是我得到的数据:

  • 在第一个循环中,程序占用150MB
  • 2小时后,经过68次循环,程序占用了220MB
  • 经过一个晚上和394次循环后,这个程序需要480MB

  • 因此,分配和释放内存(大约120 MB)的函数似乎在每次调用时都会“泄漏”1 MB。

    首先,确保在很长一段时间内(例如,如果一次迭代需要一分钟,运行几个小时)内存会继续增长。如果生长停止,那就没问题了。接下来我将尝试
    valgrind
    。然后,如果这没有帮助,你将不得不对你的代码进行二进制搜索:注释掉位,直到增长停止。首先,我将完全删除
    MKL
    库的使用(如果愿意,请留下存根),然后看看会发生什么。接下来,将向量更改为
    std::vector
    ,看看这是否有帮助。在那之后,你必须运用你的判断。

    我想我已经找到了罪魁祸首:MKL(今天的最新版本)。我使用Pardiso,下面的示例泄漏速度非常慢:大约每13秒泄漏0.1 MB,这导致夜间泄漏280 MB。这些是我从模拟中得到的数字

    如果您想尝试一下,可以使用以下工具进行编译:

    icpc -std=c++11 pardiso-leak.cpp -o main -lmkl_intel_lp64 -lmkl_core -lmkl_intel_thread -liomp5 -ldl -lpthread -lm
    
    谢谢大家的帮助。我已经向英特尔报告了这个错误

    #include <iostream>
    #include <vector>
    
    #include "mkl_pardiso.h"
    #include "mkl_types.h"
    
    int main (int argc, char const *argv[])
    {
      const auto n = std::size_t{1000};
      auto m = MKL_INT{n * n};
    
      auto values = std::vector<double>();
      auto column = std::vector<MKL_INT>();
      auto row = std::vector<MKL_INT>();
    
      row.push_back(1);
      for(std::size_t j = 0; j < n; ++j) {
        column.push_back(j + 1);
        values.push_back(1.0);
        column.push_back(j + n + 1);
        values.push_back(0.1);
        row.push_back(column.size() + 1);
      }
      for(std::size_t i = 1; i < n - 1; ++i) {
        for(std::size_t j = 0; j < n; ++j) {
          column.push_back(n * i + j - n + 1);
          values.push_back(0.1);
          column.push_back(n * i + j + 1);
          values.push_back(1.0);
          column.push_back(n * i + j + n + 1);
          values.push_back(0.1);
          row.push_back(column.size() + 1);
        }
      }
      for(std::size_t j = 0; j < n; ++j) {
        column.push_back((n - 1) * n + j - n + 1);
        values.push_back(0.1);
        column.push_back((n - 1) * n + j + 1);
        values.push_back(1.0);
        row.push_back(column.size() + 1);
      }
    
      auto y = std::vector<double>(m, 1.0);
      auto x = std::vector<double>(m, 0.0);
    
      auto pardiso_nrhs = MKL_INT{1};
      auto pardiso_max_fact = MKL_INT{1};
      auto pardiso_mnum = MKL_INT{1};
      auto pardiso_mtype = MKL_INT{11};
      auto pardiso_msglvl = MKL_INT{0};
      MKL_INT pardiso_iparm[64];
      for (int i = 0; i < 64; ++i) {
        pardiso_iparm[i] = 0;
      }
      pardiso_iparm[0] = 1;
      pardiso_iparm[1] = 2;
      pardiso_iparm[3] = 0;
      pardiso_iparm[4] = 0;
      pardiso_iparm[5] = 0;
      pardiso_iparm[7] = 0;
      pardiso_iparm[8] = 0;
      pardiso_iparm[9] = 13;
      pardiso_iparm[10] = 1;
      pardiso_iparm[11] = 0;
      pardiso_iparm[12] = 1;
      pardiso_iparm[17] = -1;
      pardiso_iparm[18] = 0;
      pardiso_iparm[20] = 0;
      pardiso_iparm[23] = 1;
      pardiso_iparm[24] = 0;
      pardiso_iparm[26] = 0;
      pardiso_iparm[27] = 0;
      pardiso_iparm[30] = 0;
      pardiso_iparm[31] = 0;
      pardiso_iparm[32] = 0;
      pardiso_iparm[33] = 0;
      pardiso_iparm[34] = 0;
      pardiso_iparm[59] = 0;
      pardiso_iparm[60] = 0;
      pardiso_iparm[61] = 0;
      pardiso_iparm[62] = 0;
      pardiso_iparm[63] = 0;
      void* pardiso_pt[64];
      for (int i = 0; i < 64; ++i) {
        pardiso_pt[i] = nullptr;
      }
    
      auto error = MKL_INT{0};
      auto phase = MKL_INT{11};
      MKL_INT i_dummy;
      double d_dummy;
      PARDISO(pardiso_pt, &pardiso_max_fact, &pardiso_mnum, &pardiso_mtype,
              &phase, &m, values.data(), row.data(), column.data(), &i_dummy,
              &pardiso_nrhs, pardiso_iparm, &pardiso_msglvl, &d_dummy,
              &d_dummy, &error);
      phase = 22;
      PARDISO(pardiso_pt, &pardiso_max_fact, &pardiso_mnum, &pardiso_mtype,
              &phase, &m, values.data(), row.data(), column.data(), &i_dummy,
              &pardiso_nrhs, pardiso_iparm, &pardiso_msglvl, &d_dummy,
              &d_dummy, &error);
      phase = 33;
      for(size_t i = 0; i < 10000; ++i) {
        std::cout << "i = " << i << std::endl;
        PARDISO(pardiso_pt, &pardiso_max_fact, &pardiso_mnum, &pardiso_mtype,
                &phase, &m, values.data(), row.data(), column.data(), &i_dummy,
                &pardiso_nrhs, pardiso_iparm, &pardiso_msglvl, y.data(),
                x.data(), &error);
      }
      phase = -1;
      PARDISO(pardiso_pt, &pardiso_max_fact, &pardiso_mnum, &pardiso_mtype,
              &phase, &m, values.data(), row.data(), column.data(), &i_dummy,
              &pardiso_nrhs, pardiso_iparm, &pardiso_msglvl, &d_dummy,
              &d_dummy, &error);
    
      return 0;
    }
    
    #包括
    #包括
    #包括“mkl_pardiso.h”
    #包括“mkl_类型.h”
    int main(int argc,char const*argv[]
    {
    const auto n=std::size_t{1000};
    自动m=MKL_INT{n*n};
    自动值=标准::向量();
    自动列=std::vector();
    自动行=标准::向量();
    行。向后推(1);
    对于(std::size_t j=0;jstd::cout使用RAII如何?您是否尝试过“内存碎片可以在不泄漏内存的情况下提高内存使用率?”是的。更重要的是,释放内存并不意味着您的操作系统必须立即将其从运行进程中清除。“出于各种原因。其中之一是我使用无符号整数作为索引”,std::vector
    也是如此。“我有一个将所有il::Vector初始化为NaN的调试模式”通过包装
    std::Vector
    ,而不是通过r来完成