这里是否有内存泄漏?
class myclass : public boost::enable_shared_from_this<myclass>{
//...
void broadcast(const char *buf){
broadcast(new std::string(buf));
}
void broadcast(std::string *buf){
boost::shared_ptr<std::string> msg(buf);
}
//...
};
(这是仍然显示问题的精简版本 - 通常我会在第二次broadcast
电话中真正开展工作!)
我的假设是第一次调用得到一些内存,然后因为我对智能指针什么都不做,第二次调用会立即删除它。简单?但是,当我运行程序时,内存会随着时间的推移而增加。然而,当我将程序中唯一的调用注释为broadcast()时,它没有!
没有broadcast()
的版本的ps输出:
%CPU %MEM VSZ RSS TIME
3.2 0.0 158068 1988 0:00
3.3 0.0 158068 1988 0:25 (12 mins later)
调用broadcast()
(在Ubuntu 10.04上,g ++ 4.4,增强1.40)
%CPU %MEM VSZ RSS TIME
1.0 0.0 158068 1980 0:00
3.3 0.0 158068 1988 0:04 (2 mins)
3.4 0.0 223604 1996 0:06 (3.5 mins)
3.3 0.0 223604 2000 0:09
3.1 0.0 223604 2000 2:21 (82 mins)
3.1 0.0 223604 2000 3:50 (120 mins)
(看到在3分钟左右的跳跃在我迄今为止尝试过的几次中是可重现的。)
调用broadcast()
(在Centos 5.6上,g ++ 4.1,提升1.41)
%CPU %MEM VSZ RSS TIME
0.0 0.0 51224 1744 0:00
0.0 0.0 51224 1744 0:00 (30s)
1.1 0.0 182296 1776 0:02 (3.5 mins)
0.7 0.0 182296 1776 0:03
0.7 0.0 182296 1776 0:09 (20 mins)
0.7 0.0 247832 1788 0:14 (34 mins)
0.7 0.0 247832 1788 0:17
0.7 0.0 247832 1788 0:24 (55 mins)
0.7 0.0 247832 1788 0:36 (71 mins)
以下是调用broadcast()
的方法(来自boost :: asio计时器),现在我想知道它是否重要:
void callback(){
//...
timer.expires_from_now(boost::posix_time::milliseconds(20));
//...
char buf[512];
sprintf(buf,"...");
broadcast(buf);
timer.async_wait(boost::bind(&myclass::callback, shared_from_this() ));
//...
}
(回调与广播功能属于同一类)
我有4个这样的计时器,我的io_service.run()
被3个线程的池调用。我的20ms超时意味着每个计时器调用broadcast()
50次/秒。我在函数开始时设置了到期时间,并在接近结束时运行计时器。遗漏的代码并没有做那么多;将调试信息输出到std :: cout可能是CPU占用最多的工作。我想有时可能会立即触发计时器;但是,我仍然看不出这会是一个什么问题,更不用说造成内存泄漏了。
(顺便说一句,该程序运行正常,即使在执行完整任务时也是如此;当我注意到ps报告的内存使用率上升时,我只会怀疑。)
更新:感谢您的回答和评论。我可以补充一点,我让程序在每个系统上运行了几个小时,内存使用量没有进一步增加。 (当Centos版本第二次跳跃时,我也准备将其视为一次性堆重组或其他东西。)无论如何,我很高兴知道我对智能指针的理解仍然是合理的,并且有没有我需要关注的带有线程的怪异角落案例。
答案 0 :(得分:2)
如果发生泄漏,则每秒50次分配std::string
(20字节,或多或少)。
在1小时内你应该被分配... 3600 * 50 * 20 = 3,4MBytes。
与你看到的64K没什么关系,这可能是由于系统将内存分配给进程的方式,new
子分配给变量。
当系统被删除时,系统需要“垃圾收集它”,将其放回可用的内存链中以进行进一步的分配。 但由于这需要时间,因此大多数系统在释放的内存超过一定数量之前不会执行此操作,因此可以执行“重新包装”。
答案 1 :(得分:1)
嗯,这里发生的事情可能不是你的程序泄漏,但由于某种原因,系统内存分配器决定为你的应用程序保留另一个64 kB的页面。如果此时存在持续的内存泄漏,以50 Hz的速率,则会产生更大的影响!
究竟为什么在3分钟之后我不知道(我不是该领域的专家),但我猜想有一些启发式和统计数据。或者,它可能只是堆已经碎片化。
可能发生的另一件事是,您在缓冲区中保存的消息会随着时间的推移变得更长:)