【发布时间】:2009-11-16 07:14:44
【问题描述】:
我正在调试这个数据库项目。它为更高级别的应用程序包装了对 SQLite 的访问。它被设计为异步运行,也就是说,它具有 ExecuteRequestAsync() 和 IsRequestReady() 等方法。当调用 ExecuteRequestAsync 时,它会产生一个 boost::thread 来完成这项工作并立即返回该函数。当更高级别的应用程序决定它不再想要运行请求的结果时,它可以调用 DumpRequest() 来取消它。由于很难优雅地取消数据库请求,因此 DumpRequest 的实现只是维护一个“清理监视器线程”,等待“完成的请求”并删除它们。所有 boost::threads 都通过 boost::shared_ptr 进行管理,例如:
boost::shared_ptr<boost::thread> my_thread = new boost::thread(boost::bind(&DBCon::RunRequest, &this_dbcon));
当它不再需要时(被取消):
vector<boost::shared_ptr<boost::thread> > threads_tobe_removed;
// some iteration
threads_tobe_removed[i].get()->join();
threads_tobe_removed.erase(threads_tobe_removed.begin()+i);
我创建了这个单元测试项目来测试执行和转储请求的机制。它运行请求并随机取消正在运行的请求,并重复数千遍。结果证明机制没问题。一切都按预期进行。
但是,通过sysinternal的Process Explorer观察单元测试项目,发现有句柄泄漏问题。每 500 次通过,句柄计数增加 1,并且永远不会返回。增加的是“事件”类型的句柄。文件和线程句柄没有增加(当然,随着线程的产生,句柄的数量也在增加,但是每一百次调用 Sleep(10000) 以等待它们被清理,以便可以观察到句柄计数)。
我没有自己管理事件句柄。它们是由 boost::thread 在创建线程时创建的。我只保证优雅地关闭线程,我不知道事件是用来做什么的。
我想知道是否有人遇到过类似的问题?这种泄漏的原因可能是什么? Process Explorer 中的这个数字是否足够可靠,可以称之为句柄泄漏?有什么办法可以追踪和修复吗?
我在 Windows Vista 上使用静态链接的 boost 1.40 和 Visual C++。
【问题讨论】:
-
在 Intel CoreDuo E6600 上生成 100 个请求并立即转储它们通常需要大约 3 秒。并且打开句柄的峰值数量在 300 左右(包括事件、线程、文件等)。当测试进入睡眠状态时,打开的句柄数逐渐下降到 65 左右。每通过 500 次,将导致“结束”数从 65 增加到 66,然后是 67。实际上每 50,000 次执行。这非常奇怪和令人沮丧。
-
“打开的句柄数逐渐减少”,因为清理监视器线程正在收集它们。
标签: c++ windows boost memory-leaks handle