c++ - 如何找出代码的哪些部分创建了最多的虚拟内存?

标签 c++ linux memory malloc

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

5 分钟后大小保持在 13 gigs,RSS 大小稳定在 5 gigs 左右。

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

我想过更改程序以一次启动每个线程,以便更容易跟踪内存分配,但在这样做之前有什么好的工具吗?

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

最佳答案

我会使用valgrind (也许运行一整夜)或者使用 Boehm GC .

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

最重要的是找到memory leaks 。如果启动后内存不增加,那就不是问题了。

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

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

<小时/>

std::set 迷你基准测试

您提到了基于百万行的大型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)。在带有 GCC 4.8.1(intel i3770K 处理器,16Gbytes RAM)的 Debian/Sid/AMD64 上,并使用 g++ -Wall -O1 tset.cc -o ./tset-01

编译该工作台

经过 32768 次迭代,因此有 32M 个元素:

total 2109592K

(上面的最后一行由 pmap 给出)

at end c=32768 Kiter clockdiff=16470.00 millisec = 503 µs/Kiter

然后是我的 zsh 中的隐式时间

./tset-01 32768 16.77s user 0.54s system 99% cpu 17.343 total

这大约是 2.1GB。因此,每个元素和 set 成员开销可能为 64.3 字节(因为 sizeof(MyElem)==16 该集合似乎每个元素的成本不可忽略,可能为 6 个单词)

关于c++ - 如何找出代码的哪些部分创建了最多的虚拟内存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18035076/

相关文章:

c++ - 是什么让一种语言不愿意/不能包含 RAII?

c++ - 是否可以在析构函数运行时不破坏 obj ?

c++ - 我可以使用类类型来转换内存区域吗?

linux - 为什么共享库(.so 文件)加载为私有(private)?

python - 即使在连接丢失或 SSH 连接终止后,如何让 python 脚本(abc.py)继续在 AWS 上执行?

c++ - 使用部分初始化数组的内存问题(在 0/1 背包中)

asp.net - 如果您的 ASP.NET 应用程序使用过多内存会发生什么情况?

c++ - 寻找系列的第 X 项

c++ - 给定一个 T 和函数名称和类型,我该如何解析 T::function?

linux - Bash crontab 不输出 shell 脚本文件的结果