TADOQuery и TADOConnection утечка памяти

Я использую C ++ Builder XE3. В службе Windows у нас есть сервер IdTCP (Indy TCP Server) в функции tcp_serverExecute (TIdContext * AContext) — который, как я понимаю, порождает новый поток.

Я создаю 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, у меня не возникает та же проблема.

0

Решение

Вы должны пройти НОЛЬ как владелец и удалить созданные объекты самостоятельно. Также опасно вызывать CoInitialize и CoUninitialize внутри потока, помещать их в конструктор форм и деструктор:

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

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

Другие решения

COM должен быть инициализирован только один раз для потока, но OnExecute событие запускается несколько раз в течение жизни клиента.

Если вы не используете пул потоков с TIdTCPServer (прикрепив TIdSchedulerOfThreadPool компонент к TIdTCPServer::Scheduler собственность), то вы можете использовать TIdTCPServer::OnConnect а также TIdTCPServer::OnDisconnect события для инициализации / завершения ваших объектов ADO, а затем использовать их в 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 вместо:

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...
}

Однако, если вы используете пул потоков, то несколько клиентов могут обслуживаться одним и тем же физическим потоком, поэтому вам следует перенести инициализацию COM в реальный объект потока, который управляет TIdContext объекты (вы также должны переместить объекты ADO в поток, чтобы их можно было повторно использовать для нескольких клиентов), например:

class TMyADOThread : public TIdThreadWithTask
{
protected:
virtual void __fastcall AfterExecute();
virtual void __fastcall BeforeExecute();

public:
TADOConnection *sql_conn;
TADOQuery *pos_q;

__fastcall TMyADOThread(TIdTask *ATask = NULL, const String AName = "");
};

__fastcall TMyADOThread::TMyADOThread(TIdTask *ATask, const String AName)
: TIdThreadWithTask(ATask, AName)
{
}

void __fastcall TMyADOThread::BeforeExecute()
{
TIdThreadWithTask::BeforeExecute();
::CoInitialize(NULL);
sql_conn = new TADOConnection(NULL);
pos_q = new TADOQuery(NULL);
}

void __fastcall TMyADOThread::AfterExecute()
{
delete pos_q;
delete sql_conn;
::CoUninitialize();
TIdThreadWithTask::AfterExecute();
}

__fastcall TMyForm::TMyForm(TComponent *Owner)
: TForm(Owner)
{
// do this before activating TIdTCPServer
IdSchedulerOfThreadPool1->ThreadClass = __classid(TMyADOThread);
}

void __fastcall TMyForm::tcp_serverExecute(TIdContext *AContext)
{
TMyADOThread *pThread = static_cast<TMyADOThread*>(static_cast<TIdYarnOfThread*>(AContext->Yarn)->Thread);
// use pThread->sql_conn and pThread->pos_q as needed...
}
0

По вопросам рекламы [email protected]