TADOQuery和TADOConnection内存泄漏

时间:2013-10-19 18:35:43

标签: c++ c++builder tadoquery

我使用的是C ++ Builder XE3。在Windows服务中,我们在函数tcp_serverExecute(TIdContext * AContext)上有(Indy TCP服务器)上的IdTCP服务器 - 据我了解产生新线程。

我创建TADOConnection和TADOQuery(在我调用CoInitialize之后) 问题是无论我做什么应用程序总是泄漏内存,除非我使用服务对象作为连接和查询的父级

  ::CoInitialize(NULL);
  TADOConnection * sql_conn = new TADOConnection(service_object);
  TADOQuery * pos_q = new TADOQuery(service_object);

try
{

}
__finally
{
  delete pos_q;
  delete sql_conn;
  ::CoUninitialize();
}

但是,如果我确实使用服务对象作为父项,我最终会得到一个异常并且应用程序崩溃。如果我为父(所有者)使用NULL工作正常,但进程在内存中保持增长。据我所知并测试我是否在TThread中执行类似的代码我没有遇到同样的问题。

2 个答案:

答案 0 :(得分:0)

你应该将 NULL 作为所有者传递并自己删除创建的对象,同时在线程内部调用CoInitialize和CoUninitialize是危险的,将它们放在表单构造函数和析构函数中:

TADOConnection * sql_conn = new TADOConnection(NULL);
TADOQuery * pos_q = new TADOQuery(NULL);

try
{
}
__finally
{
    delete pos_q;
    delete sql_conn;
}

答案 1 :(得分:0)

每个线程只应初始化一次COM,但在客户端的生命周期内会多次触发OnExecute事件。

如果您没有使用TIdTCPServer的线程池(通过将TIdSchedulerOfThreadPool组件附加到TIdTCPServer::Scheduler属性),那么您可以使用TIdTCPServer::OnConnect和{{1 }}事件初始化/完成您的ADO对象,然后根据需要在TIdTCPServer::OnDisconnect事件中使用它们,例如:

TIdTCPServer::OnExecute

或者,从class TMyContextData { public: TADOConnection *sql_conn; TADOQuery *pos_q; TMyContextData(); ~TMyContextData(); }; TMyContextData::TMyContextData() { sql_conn = new TADOConnection(NULL); pos_q = new TADOQuery(NULL); } TMyContextData::~TMyContextData() { delete pos_q; delete sql_conn; } void __fastcall TMyForm::tcp_serverConnect(TIdContext *AContext) { ::CoInitialize(NULL); AContext->Data = new TMyContextData; } void __fastcall TMyForm::tcp_serverDisconnect(TIdContext *AContext) { delete static_cast<TMyContextData*>(AContext->Data); AContext->Data = NULL; ::CoUninitialize(); } void __fastcall TMyForm::tcp_serverExecute(TIdContext *AContext) { TMyContextData *pData = static_cast<TMyContextData*>(AContext->Data); // use pData->sql_conn and pData->pos_q as needed... } 派生一个新类:

TIdServerContext

但是,如果您正在使用线程池,那么同一个物理线程可以为多个客户端提供服务,因此您应该将COM初始化移动到管理class TMyContext : public TIdServerContext { public: TADOConnection *sql_conn; TADOQuery *pos_q; __fastcall TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList = NULL); __fastcall ~TMyContext(); }; __fastcall TMyContext::TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList) : TIdServerContext(AConnection, AYarn, AList) { ::CoInitialize(NULL); sql_conn = new TADOConnection(NULL); pos_q = new TADOQuery(NULL); } __fastcall TMyContext::~TMyContext() { delete pos_q; delete sql_conn; ::CoUninitialize(); } __fastcall TMyForm::TMyForm(TComponent *Owner) : TForm(Owner) { // do this before activating TIdTCPServer tcp_server->ContextClass = __classid(TMyContext); } void __fastcall TMyForm::tcp_serverExecute(TIdContext *AContext) { TMyContext *pContext = static_cast<TMyContext*>(AContext); // use pContext->sql_conn and pContext->pos_q as needed... } 个对象的实际线程对象中(您还应该移动ADO对象进入线程,因此您可以将它们重用于多个客户端),例如:

TIdContext