您如何找出创建最多虚拟内存的代码部分?

时间:2013-08-03 16:44:03

标签: c++ linux memory malloc

我有一个启动的程序,在大约5分钟内,进程的虚拟大小约为13演出。它运行在Linux上,使用boost,gnu c ++库和各种其他第三方库。

5分钟后,尺寸保持在13演出,并且rss尺寸稳定在5演出。

我不能只在调试器中运行它,因为在启动时会启动大约30个线程,每个线程开始运行自己的代码,执行各种分配。因此,在每个断点处逐步检查并检查代码的不同部分的虚拟内存是不可行的。

我想改变程序一次启动一个线程,以便更容易跟踪内存分配,但在此之前是否有任何好的工具?

Valgrind相当慢,也许tcmalloc可以提供信息?

1 个答案:

答案 0 :(得分:0)

我会使用valgrind(或者整晚运行)或者使用Boehm GC

或者,在分配大量内存时,使用proc(5)文件系统来理解(例如通过/proc/$pid/statm& /proc/$pid/maps)。

最重要的是找到memory leaks。如果内存在启动后没有增长,则不是问题。

也许为每个类添加实例计数器可能会有所帮助(使用原子整数或互斥体来序列化它们)。

如果程序的源代码很大(例如一百万个源代码行),那么花费几天/几周是值得的,也许定制GCC编译器(例如使用MELT)可能是相关的。


a std::set minibenchmark

你提到基于百万行的大std::set

#include <set>
#include <string>
#include <string.h>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <time.h>

class MyElem
{
  int _n;
  char _s[16-sizeof(_n)];
public:
  MyElem(int k) :  _n(k)
  {
    snprintf (_s, sizeof(_s), "%d", k);
  };
  ~MyElem()
  {
    _n=0;
    memset(_s, 0, sizeof(_s));
  };
  int n() const
  {
    return _n;
  };
  std::string str() const
  {
    return std::string(_s);
  };
  bool less(const MyElem&x) const
  {
    return _n < x._n;
  };
};

bool operator < (const MyElem& l, const MyElem& r)
{
  return l.less(r);
}

typedef std::set<MyElem> MySet;

void bench (int cnt, MySet& set)
{
  for (long i=0; i<(long)cnt*1024; i++)
    set.insert(MyElem(i));
  time_t now = 0;
  time (&now);
  set.insert (((now) & 0xfffffff) * 100);
}

int main (int argc, char** argv)
{
  MySet s;
  clock_t cstart, cend;
  int c = argc>1?atoi(argv[1]):256;
  if (c<16) c=16;
  printf ("c=%d Kiter\n", c);
  cstart = clock();
  bench (c, s);
  cend = clock();
  int x = getpid();
  char cmdbuf[64];
  snprintf(cmdbuf, sizeof(cmdbuf), "pmap %d", x);
  printf ("running %s\n", cmdbuf);
  fflush (NULL);
  system(cmdbuf);
  putchar('\n');
  printf ("at end c=%d Kiter clockdiff=%.2f millisec = %.f µs/Kiter\n",
          c, (cend-cstart)*1.0e-3, (double)(cend-cstart)/c);
  if (s.find(x) != s.end())
    printf("set has %d\n", x);
  else
    printf("set don't contain %d\n", x);
  return 0;
}    

注意16个字节sizeof(MyElem)。在Debian / Sid / AMD64上使用GCC 4.8.1(intel i3770K处理器,16Gbytes RAM)并使用g++ -Wall -O1 tset.cc -o ./tset-01

编译该工作台

拥有32768千次迭代,因此32M元素:

  总共2109592K

pmap给出的上一行)

  

结束时c = 32768 Kiter clockdiff = 16470.00 millisec =503μs/ Kiter

然后来自time

的隐式zsh
  

./ tset-01 32768 16.77s用户0.54s系统99%cpu 17.343总计

这大约是2.1Gbytes。所以每个元素可能有64.3个字节&amp; set成员开销(因为sizeof(MyElem)==16该集合似乎具有每个元素可能有6个字的不可忽略的成本)