我使用C++生成器XE3。在windows服务中,我们在函数tcp_serverExecute(TIdContext *AContext)中有IdTCP服务器( Indy TCP server )-据我所知,它会产生新的线程。
我创建了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();
}
但是,如果我确实使用服务对象作为父对象,我最终会得到一个异常,并且应用程序崩溃。如果我为parent ( owner )使用NULL,则工作正常,但进程会在内存中不断增长。据我所知和测试,如果我在TThread中做类似的代码,我不会得到同样的问题。
发布于 2013-10-21 01:04:16
您应该以所有者的身份传递空并自行删除创建的对象,同时在线程内部调用CoInitialize和CoUninitialize也很危险,请将它们放在表单构造函数和析构函数中:
TADOConnection * sql_conn = new TADOConnection(NULL);
TADOQuery * pos_q = new TADOQuery(NULL);
try
{
}
__finally
{
delete pos_q;
delete sql_conn;
}
发布于 2013-11-20 11:02:24
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...
}
https://stackoverflow.com/questions/19469595
复制相似问题