TADOQuery和TADOConnection内存泄漏 我使用C++ Builder XE3。在windows服务中,我们在函数TCP_serverExecute(TIdContext*AContext)中有IdTCP服务器(Indy TCP server)——据我所知,这会产生新线程

TADOQuery和TADOConnection内存泄漏 我使用C++ Builder XE3。在windows服务中,我们在函数TCP_serverExecute(TIdContext*AContext)中有IdTCP服务器(Indy TCP server)——据我所知,这会产生新线程,c++,c++builder,tadoquery,C++,C++builder,Tadoquery,我创建TADOConnection和TADOQuery(在我调用CoInitialize之后) 问题是无论我做什么,应用程序总是泄漏内存,除非我使用服务对象作为连接和查询的父对象 ::CoInitialize(NULL); TADOConnection * sql_conn = new TADOConnection(service_object); TADOQuery * pos_q = new TADOQuery(service_object); try { } __final

我创建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中编写类似的代码并进行测试,我不会遇到同样的问题

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

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

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

每个线程只应初始化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...
 }
但是,如果您使用线程池,那么同一物理线程可以为多个客户端提供服务,因此您应该将COM初始化移动到管理
TIdContext
对象的实际线程对象中(您还应该将ADO对象移动到线程中,以便可以为多个客户端重用它们),例如:

类TMyADOThread:public TIdThreadWithTask
{
受保护的:
虚拟void uu fastcall AfterExecute();
虚拟void uu fastcall BeforeExecute();
公众:
TADOConnection*sql_conn;
TADOQuery*pos_q;
__fastcall TMyADOThread(TIdTask*ATask=NULL,常量字符串AName=”“);
};
__快速调用TMyADOThread::TMyADOThread(TIdTask*ATask,常量字符串AName)
:TIdThreadWithTask(ATask、AName)
{
}
void uu fastcall TMyADOThread::BeforeExecute()
{
TIdThreadWithTask::BeforeExecute();
::协同初始化(空);
sql_conn=新的数据连接(NULL);
pos_q=新的TADOQuery(空);
}
void uu fastcall TMyADOThread::AfterExecute()
{
删除pos_q;
删除sql_conn;
::coninitialize();
TIdThreadWithTask::AfterExecute();
}
__快速调用TMyForm::TMyForm(TComponent*Owner)
:t表格(所有者)
{
//在激活TIdTCPServer之前执行此操作
IdSchedulerOfThreadPool1->ThreadClass=\uu classid(TMyADOThread);
}
void\uu fastcall TMyForm::tcp\u serverExecute(TIdContext*AContext)
{
TMyADOThread*pThread=static_cast(static_cast(AContext->纱线)->Thread);
//根据需要使用pThread->sql\u conn和pThread->pos\u q。。。
}

是的,您应该使用
NULL
所有者,但是在这种情况下必须调用
CoInitialize/Ex()
concitialize()
,因为此代码在
TIdTCPServer
创建的工作线程中运行,因此在表单的构造函数/析构函数中调用它们不是一个选项。ADO使用COM对象,任何想要访问COM对象的工作线程都必须在创建和使用COM对象之前调用
conitialize/Ex()
,以建立线程与COM(单元线程与多线程)的关系。为什么您认为存在泄漏?进程内存的增加不一定表示存在真正的泄漏。请记住,RTL缓存并重用释放的内存,它不会返回到操作系统。您可能只是看到内存碎片,而不是内存泄漏。如果尚未安装,则应安装或安装其他旨在防止碎片的内存管理器。
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...
}
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...
}