我有一组程序与共享内存(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左右 - 因此可能没有那么快再现此错误。
因此可能存在泄漏:
是否存在可以帮助解决此类问题的其他工具/库/黑客?
编辑: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泄漏。尝试在邮件列表中找到答案。
答案 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。