内存泄漏没有valgrind打猎

时间:2013-06-04 08:47:44

标签: c memory-leaks valgrind shared-memory

我有一组程序与共享内存(ipc)一起工作~48GB。

在Linux 3.6.0-rc5中运行的程序,写成纯C,编译gcc 主计算机的平均负载为6.0,每10秒跳一次16.0(24核)

一个代理接收来自其他机器的数据0mq(3.2.3,来自同一网络中的12台机器的~1000 msgs / s),写入共享内存 许多(<50)工作人员读取此数据并进行一些计算。

代理使用大约20%的cpu 每个使用1%CPU的工人定期跳10%。

当所有分配在init()中完成时所有程序都以这样的方式编写 - 在程序启动时调用,所有在destroy()中完成免费 - 在退出之前调用

重复代码根本不使用任何malloc / calloc / free。

但两个程序仍然泄密。每分钟大约120-240字节。这不是很多 - 内存在7-8天内耗尽,我只是开始/停止进程,但每次监控应用程序向我报告此重启时,那些泄漏的字节都会让我大吃一惊:)

糟糕的事情 - 我无法使用共享内存运行valgrind - 它只是停止分配/附加共享内存然后一切都开始崩溃了。

试图找到这个泄漏我已经剥离了代理版本 - 没有泄漏,但我不能用相同数量的数据提供它。

在gdb下运行时仍然没有泄漏,但速度下降了2/3左右 - 因此可能没有那么快再现此错误。

因此可能存在泄漏:

  • 我的代码。但是没有malloc / calloc。只需指点+ - ,memcpy,memcmp
  • 一些标准库。 glibc的?系统日志?
  • 0mq使用多个来源(不要认为每秒1k / msgs是太多的流量)

是否存在可以帮助解决此类问题的其他工具/库/黑客?

编辑:Shivan Raptor询问了代码。重复部分是5k行数学。没有我提到的任何分配。

但是在这里开始,停止和重复进入:

int main(int argc, char **argv)
{
    ida_init(argc, argv, PROXY);
    ex_pollponies(); // repetive
    ida_destroy();
    return(0);
}


// with some cuttings

int ex_pollponies(void)
{
  int i, rc;
  unsigned char buf[90];
  uint64_t fos[ROLLINGBUFFERSIZE];
  uint64_t bhs[ROLLINGBUFFERSIZE];
  int bfcnt = 0;

  uint64_t *fo;
  uint64_t *bh;

  while(1) {
    rc = zmq_poll(ex_in->poll_items, ex_in->count, EX_POLL_TIMEOUT);
    for (i=0; i < ex_in->count; i++) {
      if (ex_in->poll_items[i].revents & ZMQ_POLLIN) {

        if (zmq_recv(ex_in->poll_items[i].socket, &buf, max_size, 0) == 0)
          continue;
        fo = &fos[bfcnt];
        bh = &bhs[bfcnt];
        bfcnt++;
        if (bfcnt >= ROLLINGBUFFERSIZE)
          bfcnt = 0;

        memcpy(fo, (void *)&buf[1], sizeof(FRAMEOBJECT));
        memcpy(bh, &buf[sizeof(FRAMEOBJECT)+1], sizeof(FRAMEHASH));

        // then store fo, bh into shared memory, with some adjusting and checkings
        // storing every second around 1000 msgs 16 bytes each. But leaking is only 200 bytes per minute.

      }
     }

  }
}

EDIT2:

我终于让valgrind工作 - 只是使用部分数据(6GB)并最终通过。并没有发现任何泄漏。但是,在工作过程中需要100%的CPU,而且我的程序肯定没有处理所有传入的数据 - 它不能满负荷工作。 这一半证实了我的上一次猜测 - 泄漏是在数据交换块上。 我找到有关mtrace(libc的一部分)的信息 它帮助我跟踪泄漏的地址 - 它在我的代码之外,在一个线程中。我的代码中唯一的线程是由zeromq创建的。然后我开始玩套接字的选项(增加hwm,缓冲区)和泄漏速度下降,但即使在荒谬的大值上也没有完全消失:(

所以,现在我95%确定它的zeromq泄漏。尝试在邮件列表中找到答案。

1 个答案:

答案 0 :(得分:3)

如果valgrind无法解决问题 - 您可以尝试自行跟踪内存分配。

有两种方法 - 将您对malloc的调用替换为调用您自己的malloc版本和free,并将这些函数传递给某些标识符,例如 FILE LINE ,或者您可以传入正在分配的系统的名称。

在非内存泄漏检测模式下,您直接传递给malloc和free,在内存泄漏检测模式下,您首先记录alloc和free调用,然后调用malloc和free。当程序结束时,你匹配分配和释放,你会看到你在哪里泄漏内存。

您可以使用宏来执行此操作,因此您的常规版本不会变慢。

您不会从客户端库中捕获无法自行重新编译的泄漏。

另一种方法是在链接时使用gcc的-wrap标志,让gcc调用你的malloc / free版本而不是glibc。看这篇文章:

Create a wrapper function for malloc and free in C

这样做的好处是您还可以在客户端库中记录分配。缺点是您只能使用相同的功能签名,因此您无法在泄漏检查器中获得 FILE LINE

如果这是C ++,你可以重载全局运算符new。