为什么会立即销毁共享指针泄漏内存?

问题描述:

这里有没有内存泄漏?为什么会立即销毁共享指针泄漏内存?

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的来电!) 我的假设是,在第一次调用得到了一些记忆,然后因为我做什么用第二次调用的智能指针会立即删除它。简单?但是,当我运行我的程序时,内存会随着时间的推移而增加,跳跃。然而,当我在节目中唯一打电话给广播()时,它不会!

ps的输出为版本,而不broadcast()

%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,克++ 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,boost 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超时意味着每个计时器都会以50次/秒的速度调用broadcast()。我在我的函数开始时设置了到期时间,并在接近结束时运行计时器。被遗忘的代码并没有那么做;将调试信息输出到std :: cout可能是占用CPU最多的工作。我想有时可能会立即触发计时器;但是,我仍然不明白这会是一个问题,更不用说造成内存泄漏。

(该程序运行正常,顺便说一下,做了充分的任务即使;我只当我发现通过PS报告的内存使用量已经跳起来了疑惑。)

UPDATE:感谢答案和评论。我可以补充说,我将​​程序在每个系统上运行了几个小时,内存使用量没有再增加。 (当Centos版本第二次跳转时,我也准备将其视为一次性堆重组或其他东西)。无论如何,很高兴知道我对智能指针的理解仍然健全,并且存在没有我需要关心的线程的奇怪的角落案例。

+4

1)您的代码示例不能编译。 2)在我[修复](http://ideone.com/FCPHf)之后,我将它运行在valgrind下。它不会泄漏。 – 2012-02-22 06:49:43

+1

我怀疑你正在看到堆管理的效果,而不是泄漏(例如碎片等)。有时候堆管理器可能会给你一个新的内存块,而不是重复使用现有的内存管理器来考虑性能,而且这种行为是不确定的。如果你想真正检查这些东西,请使用调试分配器(MSVC++随附一个,对于GCC,你可以像Rob那样使用Valgrind) – 2012-02-22 07:06:39

+0

如果你显示的代码是程序唯一的东西,它可能是一个问题。但是,您可能也在做其他许多事情,并且可以轻松解释其中的差异。 – 2012-02-22 07:09:43

如果有泄漏的消息,则分配一个std::string(20字节,更多或更少的)50倍每秒。 在1小时内您应该已经分配... 3600 * 50 * 20 = 3,4MBytes。

您看到的与64K无关,这可能是由于系统将内存分配给进程的方式,即new子分配给变量。

系统在删除某些内容时需要“垃圾回收”,将其重新放回可用内存链以供进一步分配。 但是,由于这需要时间,所以大部分系统都不会执行此操作,直到释放的内存超过了一定的数量,这样才能完成“重新打包”。

那么,这里发生的事情可能不是你的程序正在泄漏,但由于某种原因,系统内存分配器决定为你的应用程序保留另一个64 kB页面。如果在这一点上存在一个持续的内存泄漏,那么在50 Hz的速率下,这将会产生更为戏剧化的效果!我不知道(我不是那个领域的专家),但我猜想有一些启发式和统计数据涉及到了。我不知道(我不是这方面的专家)。或者,它可能仅仅是堆已经分散。

可能发生的另一件事是,你是保持在缓冲器变长随时间:)