freeeyes 发表于 2010-7-21 11:30:10

关于Proactor使用Handler池内存泄露的问题

最近在做一些代码的分析,遇到一个奇怪的问题。
我写了一个简单的Proactor的例子,重载了ACE_Asynch_Acceptor,并创建了一个Handler对象池,在make_handler中获得一个Handler对象,当链接断开的时候归还make_handler到池中。
但是测试发现,在多线程并行测试下,内存不断的在增长,一开始我以为MessageBlock出现的问题,后来详细测试似乎MessageBlock没有问题。随着程序的运行,内存一直在增加。很奇怪,后来我把并行客户端链接线程减少到1,依然出现这样的情况。
调试了很久,似乎依然没有什么头绪。不知道内存增量到底是哪里产生的,Proactor服务器代码很简单,基本上能删的都删了。
呵呵,希望伙伴们帮我看看,给我一些建议。
代码以附件形式贴出,包括服务器和测试客户端。
我依然怀疑内存泄露点可能存在于ACE_Message_Block的部分。

modern 发表于 2010-7-21 13:00:39

内存泄露问题用工具查一下吧。比分析代码快多了。
windows我一般用vld比较简单。
linux用valgrind也不错。

freeeyes 发表于 2010-7-21 13:44:10

我没有找到vid的工具,我一直用BoundsCheck。检测出的一些泄露都是单件的问题。

dwh0403 发表于 2010-7-21 15:00:08

本帖最后由 dwh0403 于 2010-7-21 15:21 编辑

PurenessProactor.cpp中的 typedef map<void*, _MemoryData*> mapMemory;_MemoryData好像没有定义代码中也没有使用直接屏蔽掉就可以了。

经过我的测试win7+ace5.8.0 没有发现内存明显增长的情况。 倒是两个程序一跑CPU直接100%了

freeeyes 发表于 2010-7-21 15:33:18

我在win7+ACE5.7.4上有较大内存增长。测试程序内存也有增加。

modern 发表于 2010-7-21 15:37:00

本帖最后由 modern 于 2010-7-21 15:39 编辑

VLD用起来超级简单。直接添加头文件,编个DEBUG版本看output就OK了。

obejct_manager相关那几坨内存泄露,基本都是一次的,
ACE的设计者认为这不是问题,而且改起来是一个超级大的工程,因此不会解决的。
BoundChecker是好东西,
不过貌似没有继续做下去了
我一直没有找到适合VS2008以上的版本。

winston 发表于 2010-7-21 18:24:01

这几天事情太多,还没来及看工程.boundschecker有新版本,但不叫这个名字了.devpartner - 没有能适应最新VS.Studio的版本.

freeeyes 发表于 2010-7-22 18:15:05

本帖最后由 freeeyes 于 2010-7-22 18:35 编辑

感谢modern的工具,我正在测试。。

freeeyes 发表于 2010-7-26 10:37:02

这个问题我大概找到原因了。
如果我在Handler类里面使用
ACE_Asynch_Read_Stream*    m_preader;
ACE_Asynch_Write_Stream*   m_pwriter;
每次使用的时候创建(new)。每次链接断开的时候删除(delete)。这时候内存曲就是平的,如果我使用
ACE_Asynch_Read_Stream    m_reader;
ACE_Asynch_Write_Stream   m_writer;
这个时候,当我在链接关闭的时候cancel,就会有内存泄露。原因是里面的缓冲内存块似乎没有得到释放。
因为我使用的是Handler池的方法,反复利用handler从而提高效率,减少new和delete,所以在这里存在了一个问题。
呵呵,这部分谁研究过?

winston 发表于 2010-7-26 11:58:04

我检查了一下系统的运行流程,认为找到了原因:
int
ACE_Asynch_Read_Stream::open (ACE_Handler &handler,
                              ACE_HANDLE handle,
                              const void *completion_key,
                              ACE_Proactor *proactor)
{
// Get a proactor for/from the user.
proactor = this->get_proactor (proactor, handler);

// Now let us get the implementation initialized.
if ((this->implementation_ = proactor->create_asynch_read_stream ()) == 0)
    return -1;
//这里,每次都会创建一个新的异步处理器
ACE_Asynch_Read_Stream_Impl *
ACE_WIN32_Proactor::create_asynch_read_stream (void)
{
ACE_Asynch_Read_Stream_Impl *implementation = 0;
ACE_NEW_RETURN (implementation,
                  ACE_WIN32_Asynch_Read_Stream (this),
                  0);
return implementation;
}

freeeyes的工程,为了加快速度,把handler转变成了对象池,但ACE的代码显然没考虑过这样的应用。所以每次在handler对象open的时候,无论是否已经存在异步处理器,都会创建一个新的异步处理器,这导致了内存泄漏。而把m_reader/m_writer变成指针后,则会在delete的时候,自动的清除对应的异步处理器,就没有问题了。

改进方法嘛,修改ACE,做一下存在的判断。或者放弃这个模式。
页: [1] 2
查看完整版本: 关于Proactor使用Handler池内存泄露的问题