Article ID: 198834
Article Last Modified on 9/22/2003
APPLIES TO
- Microsoft ActiveX Template Library 3.0, when used with:
- Microsoft Visual C++ 5.0 Enterprise Edition
- Microsoft Visual C++ 6.0 Enterprise Edition
- Microsoft Visual C++ 5.0 Professional Edition
- Microsoft Visual C++ 6.0 Professional Edition
- Microsoft Visual C++ 6.0 Standard Edition
- Microsoft Visual C++ .NET 2003 Standard Edition
- Microsoft Visual C++ .NET 2002 Standard Edition
This article was previously published under Q198834
SYMPTOMS
An ATL EXE with a singleton object doesn't unload from
memory even after all clients release references to it.
CAUSE
This problem can occur if your singleton class contains an
inner object that increments the module lock count. Consider the following
code, where CMySingletonComponent and CMyInnerObject are ATL "Simple Objects":
class CMySingletonComponent : public CComCoClass<...>, ...
{
public:
DECLARE_CLASSFACTORY_SINGLETON(CMySingletonComponent)
CComObject<CMyInnerObject>* m_pInner;
HRESULT FinalConstruct ()
{
return CComObject<CMyInnerObject>::CreateInstance (&m_pInner);
}
void FinalRelease ()
{
delete m_pInner;
}
...
};
An ATL local server doesn't unload until the module lock
count goes to zero, which in the case above never happens, because the
CComObject<> contained inside the singleton class above increments the
module lock count in its constructor but is never given a chance to decrement
it in its destructor.
The contained CComObject<>'s destructor
is called only if the singleton is destroyed. The singleton is destroyed only
if the class factory is destroyed. The class factory in turn is destroyed only
if the module lock count goes to zero, which can't happen because the
CComObject<> in the singleton is never destroyed and doesn't decrement
the module lock count.
RESOLUTION
Use a class that doesn't increment the module lock count.
You can use CComObjectNoLock<> in place of CComObject<> for this
purpose:
class CMySingletonComponent : public CComCoClass<...>, ...
{
public:
DECLARE_CLASSFACTORY_SINGLETON(CMySingletonComponent)
CComObjectNoLock<CMyInnerObject>* m_pInner;
HRESULT FinalConstruct ()
{
m_pInner = new CComObjectNoLock<CMyInnerObject>;
ATLASSERT (m_pInner);
return m_pInner->FinalConstruct();
}
void FinalRelease ()
{
delete m_pInner;
}
...
};
STATUS
This behavior is by design.
REFERENCES
(c) Microsoft Corporation 1999, All Rights Reserved.
Contributions by Samson Tanrena, Microsoft Corporation.
Additional query words: kbDSupport hang hangs stays exit remove
removed
Keywords: kblocalsvr kbprb KB198834