2013-10-19 3 views
0

C++ Builder XE3을 사용합니다. 윈도우 서비스에서 우리는 IdPCP 서버 (Indy TCP Server)를 tcp_serverExecute (TIdContext * AContext) 함수에 넣었습니다. 이것은 새로운 스레드를 생성하는 것으로 이해합니다.TADOQuery 및 TADOConnection 메모리 누수

내가 만들 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에서 비슷한 코드를 수행하면 동일한 문제가 발생하지 않습니다.

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

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

누수가 있다고 생각되는 이유는 무엇입니까? 프로세스 메모리의 증가가 실제 누설을 나타내는 것은 아닙니다. RTL이 캐시하고 해제 된 메모리를 다시 사용한다는 것을 기억하십시오. 다시 OS로 돌아 가지 않습니다. 메모리 누수가 아닌 메모리 단편화 만 보일 수 있습니다. 아직 설치하지 않은 경우 [FastMM] (http://fastmm.sourrceforge.net) 또는 조각화를 방지하도록 설계된 다른 메모리 관리자를 설치해야합니다. –

답변

0

당신은 소유자NULL을 통과해야하고 위험 또한 스레드 내부으로 CoInitialize 및 CoUninitialize를 호출 만든 개체를 직접 삭제 스레드 당 한 번, 클라이언트의 수명 동안 OnExecute 이벤트가 여러 번 트리거됩니다. 당신이합니다 (TIdTCPServer::Scheduler 속성에 TIdSchedulerOfThreadPool 구성 요소를 연결하여) TIdTCPServer 풀링 스레드를 사용하지 않는 경우

은, 당신은/초기화하여 ADO 개체를 마무리 한 후 TIdTCPServer::OnExecute 이벤트로에서 사용하는 TIdTCPServer::OnConnectTIdTCPServer::OnDisconnect 이벤트를 사용할 수 있습니다 필요한, 예를 들면 :

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

네,'NULL' 소유자를 사용해야합니다. 그러나이 코드는 TIdTCPServer가 생성 한 작업자 스레드에서 실행 중이기 때문에'CoInitialize/Ex()'와'CoUniitialize()'를 호출해야합니다. Form의 생성자/소멸자는 옵션이 아닙니다. ADO는 COM 개체를 사용하고 COM 개체에 액세스하려는 작업자 스레드는 COM 개체를 만들고 사용하기 전에 COM (아파트 스레드 대 다중 스레드)과의 스레드 관계를 설정하기 위해 CoIntialize/Ex()를 호출해야합니다. –

0

COM은 초기화 할 필요가 폼 생성자와 소멸자에 넣어,