我使用的是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中执行类似的代码我没有遇到同样的问题。
答案 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